




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、數(shù)據(jù)庫連接及線程池曾幾何時,記住了一句話:“建立數(shù)據(jù)庫連接是一個代價高昂的過程”,也從那時開始,我在構(gòu)建系統(tǒng)時,一旦建立起了數(shù)據(jù)庫連接,就保存起來,任何要用數(shù)據(jù)庫的地方,都使用這個數(shù)據(jù)庫連接對象進行操作。 這樣的行為,在以前寫的單線程程序中,倒也可以接受,但在這次寫的多線程程序中,就出現(xiàn)問題了。在這次的程序中,最開始設(shè)計時,在工作線程類中,設(shè)置了一個SqlConnection的靜態(tài)成員以接受系統(tǒng)中已經(jīng)建立起的數(shù)據(jù)庫連接對象。大致的代碼如下:public class NoPoolThread
2、 public static System.Data.SqlClient.SqlConnection DatabaseConnection = null; private System.Threading.Thread WorkThread = null;
3、 private bool Continue = false; public void Start( if (WorkThread = null
4、60; ThreadStart workfun = new ThreadStart(DoWork; WorkThread = new Thread(
5、workfun; Continue = true; WorkThread.Start(;
6、 private void DoWork( System.Diagnostics.Debug.Assert(DatabaseConnec
7、tion != null; while (Continue
8、160; /省略了使用數(shù)據(jù)庫連接對象進行操作的代碼 Thread.Sleep(300; / end while
9、160; public void Stop( if (WorkThread != null
10、; Continue = false;
11、 在主程序中,使用下面的代碼來啟動工作線程SqlConnection connection = null;NoPoolThread threads = new NoPoolThread99; private void button1_Click(object sender, EventArgs econnection = new SqlConnect
12、ion(GetConnectString(; connection.Open(; NoPoolThread.DatabaseConnection = connection; for ( int i=0; i threadsi = new NoPoolThre
13、ad(; threadsi.Start(; 憑借以往的經(jīng)驗,滿心期望著:NoPoolThread你給我好好干吧,成功就在眼前。殊不知,異常馬上就出現(xiàn),基本上是說:“已有打開的與此命令相關(guān)聯(lián)的 DataReader,必須首先將它關(guān)閉。ExecuteNonQuery 要求已打開且可用的連接。連接的當(dāng)前狀態(tài)為已關(guān)閉”。
14、60; 然后把threads數(shù)組長度改成1,即又恢復(fù)到只有一個線程使用數(shù)據(jù)庫連接對象時,就又恢復(fù)正常。 這樣就說明了,在多個線程中使用同一個SqlConnection對象進行數(shù)據(jù)庫操作的想法是不現(xiàn)實的也是行不通的。 于是,就大著膽子,冒著“巨大的代價”,進行修改,在任何使用SqlConnect
15、ion的地方,都臨時創(chuàng)建的SqlConnection對象一個對象,但是要創(chuàng)建對象,需要連接字符串啊,怎么來呢,不想重新寫一遍,就用現(xiàn)成的、已經(jīng)傳到線程對象里面的哪個數(shù)據(jù)庫連接對象里面的連接字符串吧,于是修改代碼如下:private void DoWork( System.Diagnostics.Debug.Assert(DatabaseConnection != null;SqlConnection connection = new SqlConnection(DatabaseConnection.ConnectionString;
16、160; while (Continue /使用connection對象 Thread.Sleep(300;
17、60; / end while connection.Close(; 3.2 SqlConnection的連接 這樣修改的結(jié)果,每個線程使用自己的SqlConnection對象對數(shù)據(jù)庫進行操作,使各個線程之間互不影響。根據(jù)測試,程序可以順暢運行,而且在性能上沒有明顯損失,這多少有些以為,于是繼續(xù)查找資料。由于使用的時SqlConnection對象,所以就以它為線索,首先從MSDN開始,MS
18、DN給出的解釋有如下內(nèi)容:Ø SqlConnection 對象表示與 SQL Server 數(shù)據(jù)源的一個唯一的會話。對于客戶端/服務(wù)器數(shù)據(jù)庫系統(tǒng),它等效于到服務(wù)器的網(wǎng)絡(luò)連接。SqlConnection 與 SqlDataAdapter 和 SqlCommand 一起使用,可以在連接 Microsoft SQL Server 數(shù)據(jù)庫時提高性能。對于所有第三方 SQL
19、0;服務(wù)器產(chǎn)品以及其他支持 OLE DB 的數(shù)據(jù)源,請使用 OleDbConnection。Ø 當(dāng)創(chuàng)建 SqlConnection 的實例時,所有屬性都設(shè)置為它們的初始值。有關(guān)這些值的列表,請參見 SqlConnection 構(gòu)造函數(shù)。Ø 如果 SqlConnection 超出
20、范圍,則不會將其關(guān)閉。因此,必須通過調(diào)用 Close 或 Dispose 顯式關(guān)閉該連接。它們在功能上是等效的。如果將連接池值 Pooling 設(shè)置為 true 或 yes,則也會釋放物理連接。還可以打開 using 塊內(nèi)部的連接,以確保當(dāng)代碼退出 using 塊時關(guān)閉該連接。Ø 注意:若要部署高性能應(yīng)用程序,則必須使用連接池。在使用用于 S
21、QL Server 的 .NET Framework 數(shù)據(jù)提供程序時,不必啟用連接池,因為提供程序會自動對此進行管理,不過您可以修改某些設(shè)置。 從上面的解釋來看,我修改后的代碼,無意間啟用了數(shù)據(jù)庫連接池因為除非你在連接字符串里面明確禁用連接池功能,否則默認的數(shù)據(jù)庫連接是從連接池中獲得連接的。 3.3 連接池的相關(guān)概念這里,既然提及了連接池,自己在這方面的認識又很模糊,于是就自己給自己了一個學(xué)習(xí)
22、連接池的機會。連接池及ADO.NET連接到數(shù)據(jù)庫服務(wù)器通常由幾個需要很長時間的步驟組成。必須建立物理通道(例如套接字或命名管道),必須與服務(wù)器進行初次握手,必須分析連接字符串信息,必須由服務(wù)器對連接進行身份驗證,必須運行檢查以便在當(dāng)前事務(wù)中登記,等等。這就是建立數(shù)據(jù)庫連接的代價,但仍然只是定性的描述。 實際上,大多數(shù)應(yīng)用程序僅使用一個或幾個不同的連接配置。這意味著在執(zhí)行應(yīng)用程序期間,許多相同的連接將反復(fù)地打開和關(guān)閉。為了使打開的連接成本最低,ADO.NET 使用稱為連接池的優(yōu)化方法。 連接池是一種在打開數(shù)據(jù)存儲區(qū)的連接時提高應(yīng)用程序性能的機制,可以顯著提高應(yīng)用程序
23、的性能和可縮放性。使用連接池減少新連接需要打開的次數(shù)。 池進程保持物理連接的所有權(quán)。通過為每個給定的連接配置保留一組活動連接來管理連接。只要用戶在連接上調(diào)用 Open,池進程就會檢查池中是否有可用的連接。如果某個池連接可用,會將該連接返回給調(diào)用者,而不是打開新連接。應(yīng)用程序在該連接上調(diào)用 Close 時,池進程會將連接返回到活動連接池集中,而不是真正關(guān)閉連接。連接返回到池中之后,即可在下一個 Open 調(diào)用中重復(fù)使用。 只有配置相同的連接可以建立池連接。ADO.NET 同時保留多個池,每個配置一個池。連接由連接字符
24、串以及 Windows 標(biāo)識(在使用集成的安全性時)分為多個池。 池連接可以大大提高應(yīng)用程序的性能和可縮放性,考慮一個訪問SQL Server數(shù)據(jù)庫的典型ASP.NET或WebServices應(yīng)用程序??蛻舳藨?yīng)用程序每次需要查詢數(shù)據(jù)庫時,就會在服務(wù)器端代碼中進行往返,以打開SqlConnection來執(zhí)行查詢。在許多此類應(yīng)用程序中,這一代碼以相同憑據(jù)一次又一次地連接到相同數(shù)據(jù)庫。理論上,這意味著客戶端應(yīng)用程序每次需要執(zhí)行查詢時,服務(wù)器端代碼需要執(zhí)行三個操作登錄到數(shù)據(jù)庫(需要檢查所提供的憑據(jù)、執(zhí)行查詢、然后注銷。連接池可以真正地提高此類應(yīng)用程序的性能通過將內(nèi)部連接存
25、儲在池中,并在以后進行重復(fù)利用,就不再因為登錄數(shù)據(jù)庫以及從中注銷而降低性能。對SqlConnection對象的Open和Close方法的調(diào)用可以短時間內(nèi)返回,從而可以提高代碼的性能和響應(yīng)速度(請參見3.1圖。圖3.1 典型ASP.NET或WebServices應(yīng)用程序中的連接池 默認情況下,ADO.NET 中啟用連接池。除非顯式禁用,否則,連接在應(yīng)用程序中打開和關(guān)閉時,池進程將對連接進行優(yōu)化。還可以提供幾個連接字符串修飾符來控制連接池的行為。有關(guān)更多信息,請參見MSDN中的“使用連接字符串關(guān)鍵字控制連接池”。 在調(diào)用SqlConnection對象的Clo
26、se方法時,SQL Client .NET數(shù)據(jù)提供程序并不實際關(guān)閉內(nèi)部連接。相反,數(shù)據(jù)提供程序?qū)⒃搩?nèi)部連接存儲到一個池中,以便在以后再次使用。甚至在SqlConnection對象被處理之后,該內(nèi)部連接也保留在池中。如果在以后使用相同連接字符串和憑據(jù)調(diào)用SqlConnection對象的Open方法,將會再次使用同一內(nèi)部連接與數(shù)據(jù)庫進行通信。 因此,微軟建議在使用完連接時一定要關(guān)閉或斷開連接,以便連接可以返回池。要關(guān)閉連接,可以使用 Connection 對象的 Close 或 Dispose 方法,也可以通過在 C#
27、 的 using 語句中或在 Visual Basic 的Using 語句中打開所有連接。不是顯式關(guān)閉的連接可能不會添加或返回到池中。例如,如果連接已超出范圍但沒有顯式關(guān)閉,則僅當(dāng)達到最大池大小而該連接仍然有效時,該連接才會返回到連接池中。不是顯式關(guān)閉的連接可能無法返回池。例如,如果連接已超出范圍但沒有顯式關(guān)閉,則僅當(dāng)達到最大池大小而該連接仍然有效時,該連接才會返回到連接池中。參見下面的示例。 另外,如果你希望確認是否真正再次利用了同一內(nèi)部連接,可以使用.NET Reflection中的功能以可編程方式訪問私有InnerCo
28、nnection屬性的內(nèi)容。以下代碼(其需要對System.Reflection命名空間的引用在Using代碼塊中打開一個SqlConnection,并存儲SqlConnection的InnerConnection屬性的值。通過利用Using代碼塊,在該代碼塊的末尾隱式處理了SqlConnection。此代碼在Using代碼塊中打開另一個SqlConnection,并存儲SqlConnection的InnerConnection屬性的值。最后,此代碼對比InnerConnection屬性的內(nèi)容,確認它們實際上為同一對象。string strConn = "Data Source=.S
29、QLExpress;Integrated Security=True;"PropertyInfo propInnerConn;propInnerConn = typeof(SqlConnection.GetProperty("InnerConnection",
30、0; BindingFlags.NonPublic | BindingFlags.Instance;object objInnerConn1, objInnerConn2;using (SqlConnection cn = new SqlConnection(strConn cn.Open(; objInnerConn1 = propInnerConn.GetValue(cn, null; cn.Close(; usin
31、g (SqlConnection cn = new SqlConnection(strConn cn.Open(; objInnerConn2 = propInnerConn.GetValue(cn, null; cn.Close(; Console.WriteLine(objInnerConn1 = objInnerConn2; 兩個SqlConnection對象是在不同的Using代碼塊中創(chuàng)建的,所以其資源將在每個Using代碼塊的末尾被清除。InnerConne
32、ction屬性的內(nèi)容及其所封裝的物理連接沒有被處理,而是存儲在池中,以便在以后被再次利用。 注意 如果在連接字符串中禁用了連接池(稍后將解釋如何禁用,將會看到此內(nèi)部連接不能被重復(fù)利用。 連接池的創(chuàng)建和清除 在初次打數(shù)據(jù)庫開連接時例如調(diào)用SqlConnection.Open方法時,池進程將根據(jù)完全匹配算法創(chuàng)建連接池,該算法將池與連接中的連接字符串關(guān)聯(lián)。每個連接池與不同的連接字符串關(guān)聯(lián)。打開新連接時,如果連接字符串并非與現(xiàn)有池完全匹配,將創(chuàng)建一個新池。
33、按進程、按應(yīng)用程序域、按連接字符串以及(在使用集成的安全性時)按 Windows 標(biāo)識來建立池連接。 ADO.NET 2.0 引入了兩種新的方法來清除池:ClearAllPools 和 ClearPool。ClearAllPools 清除給定提供程序的連接池,ClearPool 清除與特定連接關(guān)聯(lián)的連接池。如果在調(diào)用時連接正在使用,將進行相應(yīng)的標(biāo)記。連接關(guān)閉時,將被丟棄,而不是返回池中。 連接的添加和移除
34、60; 連接池是為每個唯一的連接字符串創(chuàng)建的。當(dāng)創(chuàng)建一個池后,將創(chuàng)建多個連接對象并將其添加到該池中,以滿足最小池大小的要求。連接根據(jù)需要添加到池中,但是不能超過指定的最大池大小(默認值為 100)。連接在關(guān)閉或斷開時釋放回池中。在請求 SqlConnection 對象時,如果存在可用的連接,將從池中獲取該對象。連接要可用,必須未使用,具有匹配的事務(wù)上下文或未與任何事務(wù)上下文關(guān)聯(lián),并且具有與服務(wù)器的有效鏈接。連接池進程通過在連接釋放回池中時重新分配連接,來滿足這些連接請求。如果已達到最大池大小且不存在可用的連接,則該請求
35、將會排隊。然后,池進程嘗試重新建立任何連接,直到到達超時時間(默認值為 15 秒)。如果池進程在連接超時之前無法滿足請求,將引發(fā)異常。 連接池進程定期掃描連接池,查找沒有通過 Close 或 Dispose 關(guān)閉的未用連接,并重新建立找到的連接。如果應(yīng)用程序沒有顯式關(guān)閉或斷開其連接,連接池進程可能需要很長時間才能重新建立連接,所以,最好確保在連接中顯式調(diào)用 Close 和 Dispose。如果連接長時間空閑,或池
36、進程檢測到與服務(wù)器的連接已斷開,連接池進程會將該連接從池中移除。注意,只有在嘗試與服務(wù)器進行通信之后才能檢測到斷開的連接。如果發(fā)現(xiàn)某連接不再連接到服務(wù)器,則會將其標(biāo)記為無效。無效連接只有在關(guān)閉或重新建立后,才會從連接池中移除。如果存在與已消失的服務(wù)器的連接,那么即使連接池管理程序未檢測到已斷開的連接并將其標(biāo)記為無效,仍有可能將此連接從池中取出。這種情況是因為檢查連接是否仍有效的系統(tǒng)開銷將造成與服務(wù)器的另一次往返,從而抵消了池進程的優(yōu)勢。發(fā)生此情況時,初次嘗試使用該連接將檢測連接是否曾斷開,并引發(fā)異常。 上述連接的添加和移除,全都是由后臺運行的池進程管理的。 禁用連接池您可能
37、不希望使用連接池。例如,如果正在使用一個直接與數(shù)據(jù)庫進行通信的簡單Windows應(yīng)用程序,那么可能希望禁用連接池。在采用這一架構(gòu)時,各個客戶端應(yīng)用程序需要自己的連接。在啟用連接池時,每個應(yīng)用程序的連接被放入池中,如果在清除連接池之前重新打開該連接,將重復(fù)利用放入池中的連接。所以,如果應(yīng)用程序頻繁重復(fù)使用連接,那么在啟用連接池的情況下,對SqlConnection.Open的調(diào)用將會更快速地返回。但是,這種方法將會導(dǎo)致在任意給定時刻存在許多活動的數(shù)據(jù)庫連接。禁用連接池將會降低任意時刻的活動數(shù)據(jù)庫連接數(shù)目,但這樣會強制所有對SqlConnection.Open的調(diào)用都建立一個新的數(shù)據(jù)庫連接。
38、60;如果希望禁用連接池,可以通過向連接字符串中添加Pooling=False,逐個連接地禁用連接池。幸運的是,在ADO.NET 2.0中不再需要記憶諸如此類的屬性。如果存在疑問,可以檢查SqlConnectionStringBuilder類的選項。在這個類中可以找到一個Pooling屬性,其取值為Boolean類型。默認情況下,此值被設(shè)置為True。將該值設(shè)置為False將會禁止將該連接放入池中。因此,在調(diào)用SqlConnection對象的Close方法時,將會關(guān)閉與數(shù)據(jù)庫的實際連接。注意 在“偶爾進行連接”的Windows應(yīng)用程序中,使用連接池
39、可能很有幫助,具體取決于應(yīng)用程序。如果應(yīng)用程序希望定期重新連接到數(shù)據(jù)庫,則可以發(fā)揮連接池的作用,將與數(shù)據(jù)庫的物理連接保持打開狀態(tài),至少暫時如此。如果在從池中刪除該物理連接之前,應(yīng)用程序嘗試重新連接到該數(shù)據(jù)庫,則連接池邏輯(pooling logic將會重新使用與該數(shù)據(jù)庫的物理連接。 查看數(shù)據(jù)庫連接 在使用了數(shù)據(jù)庫連接池的情況下,那么建立到數(shù)據(jù)庫上的連接到底怎么樣呢,這可以使用Windows的性能查看器來看。在運行SqlServer的服務(wù)器上,使用【管理工具】【性能】就可以調(diào)出性能查看器,然后添加計數(shù)器:
40、1、在性能對象下拉框中選擇:SQLServer:General Statistics,然后選擇User Connections計數(shù)器,這樣就可以看到連接到SQL Server上的數(shù)據(jù)庫連接數(shù)了。 為此,做了一個測試函數(shù),該函數(shù)不斷的建立數(shù)據(jù)庫連接,讀取userinfo表的總函數(shù),然后返回,代碼如下。private int GetNextAge(
41、160; string sql = "SELECT COUNT(username FROM userinfo" int nextage = -1;
42、;try SqlConnection connection = new SqlConnection(ConnectString;
43、60; connection.Open(;
44、0; SqlDataAdapter da = new SqlDataAdapter(sql, connection; DataSet ds = new DataSet(; da.Fill(ds; if (ds.Tables.Count != 0 &&
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 古典書架采購合同范本
- 乙方轉(zhuǎn)讓合同范本
- 醫(yī)療配件運輸合同范本
- 協(xié)助收購合同范本
- 中學(xué)體育教師先進事跡材料
- 中國大學(xué)生自強之星事跡材料
- 世界濕地日宣傳活動總結(jié)
- 個人轉(zhuǎn)讓鮮奶配送合同范本
- 叉車 轉(zhuǎn)讓合同范本
- 集控運行初級工模擬練習(xí)題及答案
- 新版《醫(yī)療器械經(jīng)營質(zhì)量管理規(guī)范》(2024)培訓(xùn)試題及答案
- 學(xué)術(shù)論文寫作與規(guī)范課件
- 口腔診所藥品管理制度
- 中醫(yī)子午流注十二時辰養(yǎng)生法
- 養(yǎng)老院風(fēng)險管控手冊
- 標(biāo)準(zhǔn)田字格帶拼音模板空白A4直接打印
- 小學(xué)語文 部編版 六年級下冊 第二單元 習(xí)作《寫作品梗概》
- 4.7 數(shù)學(xué)建?;顒樱荷L規(guī)律的描述教學(xué)設(shè)計
- 余杭區(qū)住宅房屋裝修備案申請表
- 住宅建筑工程施工重點與難點應(yīng)對措施方案
- 中醫(yī)婦科病證診斷療效標(biāo)準(zhǔn)
評論
0/150
提交評論