|
連接到數(shù)據(jù)庫(kù)服務(wù)器通常由幾個(gè)需要很長(zhǎng)時(shí)間的步驟組成。必須建立物理通道(例如套接字或命名管道),必須與服務(wù)器進(jìn)行初次握手,必須分析連接字符串信息,必須由服務(wù)器對(duì)連接進(jìn)行身份驗(yàn)證,必須運(yùn)行檢查以便在當(dāng)前事務(wù)中登記,等等。 實(shí)際上,大多數(shù)應(yīng)用程序僅使用一個(gè)或幾個(gè)不同的連接配置。這意味著在執(zhí)行應(yīng)用程序期間,許多相同的連接將反復(fù)地打開和關(guān)閉。為了使打開的連接成本最低,ADO.NET 使用稱為連接池的優(yōu)化方法。 連接池減少新連接需要打開的次數(shù)。池進(jìn)程保持物理連接的所有權(quán)。通過(guò)為每個(gè)給定的連接配置保留一組活動(dòng)連接來(lái)管理連接。只要用戶在連接上調(diào)用 Open,池進(jìn)程就會(huì)檢查池中是否有可用的連接。如果某個(gè)池連接可用,會(huì)將該連接返回給調(diào)用者,而不是打開新連接。應(yīng)用程序在該連接上調(diào)用 Close 時(shí),池進(jìn)程會(huì)將連接返回到活動(dòng)連接池集中,而不是真正關(guān)閉連接。連接返回到池中之后,即可在下一個(gè) Open 調(diào)用中重復(fù)使用。 只有配置相同的連接可以建立池連接。ADO.NET 同時(shí)保留多個(gè)池,每個(gè)配置一個(gè)池。連接由連接字符串以及 Windows 標(biāo)識(shí)(在使用集成的安全性時(shí))分為多個(gè)池。 池連接可以大大提高應(yīng)用程序的性能和可縮放性。默認(rèn)情況下,ADO.NET 中啟用連接池。除非顯式禁用,否則,連接在應(yīng)用程序中打開和關(guān)閉時(shí),池進(jìn)程將對(duì)連接進(jìn)行優(yōu)化。還可以提供幾個(gè)連接字符串修飾符來(lái)控制連接池的行為。有關(guān)更多信息,請(qǐng)參見(jiàn)本主題后面的“使用連接字符串關(guān)鍵字控制連接池”。 池的創(chuàng)建和分配在初次打開連接時(shí),將根據(jù)完全匹配算法創(chuàng)建連接池,該算法將池與連接中的連接字符串關(guān)聯(lián)。每個(gè)連接池與不同的連接字符串關(guān)聯(lián)。打開新連接時(shí),如果連接字符串并非與現(xiàn)有池完全匹配,將創(chuàng)建一個(gè)新池。按進(jìn)程、按應(yīng)用程序域、按連接字符串以及(在使用集成的安全性時(shí))按 Windows 標(biāo)識(shí)來(lái)建立池連接。 在以下 C# 示例中創(chuàng)建了三個(gè)新的 SqlConnection 對(duì)象,但是管理時(shí)只需要兩個(gè)連接池。注意,根據(jù)為 Initial Catalog 分配的值,第一個(gè)和第二個(gè)連接字符串有所不同。 using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=Northwind"))
{
connection.Open();
// Pool A is created.
}
using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=pubs"))
{
connection.Open();
// Pool B is created because the connection strings differ.
}
using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=Northwind"))
{
connection.Open();
// The connection string matches pool A.
}
如果 MinPoolSize 在連接字符串中未指定或指定為零,池中的連接將在一段時(shí)間不活動(dòng)后關(guān)閉。但是,如果指定的 MinPoolSize 大于零,在 AppDomain 被卸載并且進(jìn)程結(jié)束之前,連接池不會(huì)被破壞。非活動(dòng)或空池的維護(hù)只需要最少的系統(tǒng)開銷。
添加連接連接池是為每個(gè)唯一的連接字符串創(chuàng)建的。當(dāng)創(chuàng)建一個(gè)池后,將創(chuàng)建多個(gè)連接對(duì)象并將其添加到該池中,以滿足最小池大小的要求。連接根據(jù)需要添加到池中,但是不能超過(guò)指定的最大池大?。J(rèn)值為 100)。連接在關(guān)閉或斷開時(shí)釋放回池中。 在請(qǐng)求 SqlConnection 對(duì)象時(shí),如果存在可用的連接,將從池中獲取該對(duì)象。連接要可用,必須未使用,具有匹配的事務(wù)上下文或未與任何事務(wù)上下文關(guān)聯(lián),并且具有與服務(wù)器的有效鏈接。 連接池進(jìn)程通過(guò)在連接釋放回池中時(shí)重新分配連接,來(lái)滿足這些連接請(qǐng)求。如果已達(dá)到最大池大小且不存在可用的連接,則該請(qǐng)求將會(huì)排隊(duì)。然后,池進(jìn)程嘗試重新建立任何連接,直到到達(dá)超時(shí)時(shí)間(默認(rèn)值為 15 秒)。如果池進(jìn)程在連接超時(shí)之前無(wú)法滿足請(qǐng)求,將引發(fā)異常。
移除連接連接池進(jìn)程定期掃描連接池,查找沒(méi)有通過(guò) Close 或 Dispose 關(guān)閉的未用連接,并重新建立找到的連接。如果應(yīng)用程序沒(méi)有顯式關(guān)閉或斷開其連接,連接池進(jìn)程可能需要很長(zhǎng)時(shí)間才能重新建立連接,所以,最好確保在連接中顯式調(diào)用 Close 和 Dispose。 如果連接長(zhǎng)時(shí)間空閑,或池進(jìn)程檢測(cè)到與服務(wù)器的連接已斷開,連接池進(jìn)程會(huì)將該連接從池中移除。注意,只有在嘗試與服務(wù)器進(jìn)行通信之后才能檢測(cè)到斷開的連接。如果發(fā)現(xiàn)某連接不再連接到服務(wù)器,則會(huì)將其標(biāo)記為無(wú)效。無(wú)效連接只有在關(guān)閉或重新建立后,才會(huì)從連接池中移除。 如果存在與已消失的服務(wù)器的連接,那么即使連接池管理程序未檢測(cè)到已斷開的連接并將其標(biāo)記為無(wú)效,仍有可能將此連接從池中取出。這種情況是因?yàn)闄z查連接是否仍有效的系統(tǒng)開銷將造成與服務(wù)器的另一次往返,從而抵消了池進(jìn)程的優(yōu)勢(shì)。發(fā)生此情況時(shí),初次嘗試使用該連接將檢測(cè)連接是否曾斷開,并引發(fā)異常。 清除池ADO.NET 2.0 引入了兩種新的方法來(lái)清除池:ClearAllPools 和 ClearPool。ClearAllPools 清除給定提供程序的連接池,ClearPool 清除與特定連接關(guān)聯(lián)的連接池。如果在調(diào)用時(shí)連接正在使用,將進(jìn)行相應(yīng)的標(biāo)記。連接關(guān)閉時(shí),將被丟棄,而不是返回池中。 事務(wù)支持連接是根據(jù)事務(wù)上下文來(lái)從池中取出并進(jìn)行分配的。除非在連接字符串中指定了 Enlist=false,否則,連接池將確保連接在 Current 上下文中登記。如果連接使用登記的 System.Transactions 事務(wù)關(guān)閉并返回池中,連接將保留在池中,以便使用相同 System.Transactions 事務(wù)對(duì)該連接池的下一次請(qǐng)求將返回相同的連接。如果該事務(wù)沒(méi)有可用連接,在該連接打開時(shí),將自動(dòng)注冊(cè)該連接。 當(dāng)連接關(guān)閉時(shí),它將被釋放回池中,并根據(jù)其事務(wù)上下文放入相應(yīng)的子部分。因此,即使分布式事務(wù)仍然掛起,仍可以關(guān)閉該連接而不會(huì)生成錯(cuò)誤。這樣,您就可以在隨后提交或中止分布式事務(wù)。 使用連接字符串關(guān)鍵字控制連接池SqlConnection 對(duì)象的 ConnectionString 屬性支持連接字符串鍵/值對(duì),可以用于調(diào)整連接池邏輯的行為。有關(guān)更多信息,請(qǐng)參見(jiàn) ConnectionString。 池碎片池碎片是許多 Web 應(yīng)用程序中的一個(gè)常見(jiàn)問(wèn)題,應(yīng)用程序可能會(huì)創(chuàng)建大量在進(jìn)程退出后才會(huì)釋放的池。這樣,將打開大量的連接,占用許多內(nèi)存,從而影響性能。 因?yàn)榧砂踩援a(chǎn)生的池碎片連接根據(jù)連接字符串以及用戶標(biāo)識(shí)來(lái)建立池連接。因此,如果使用網(wǎng)站上的基本身份驗(yàn)證或 Windows 身份驗(yàn)證以及集成的安全登錄,每個(gè)用戶將獲得一個(gè)池。盡管這樣可以提高單個(gè)用戶的后續(xù)數(shù)據(jù)庫(kù)請(qǐng)求的性能,但是該用戶無(wú)法利用其他用戶建立的連接。這樣還使每個(gè)用戶至少產(chǎn)生一個(gè)與數(shù)據(jù)庫(kù)服務(wù)器的連接。這對(duì)特定 Web 應(yīng)用程序結(jié)構(gòu)會(huì)產(chǎn)生副作用,因?yàn)殚_發(fā)人員需要衡量安全性和審計(jì)要求。 因?yàn)樵S多數(shù)據(jù)庫(kù)產(chǎn)生的池碎片許多 Internet 服務(wù)提供商在一臺(tái)服務(wù)器上托管多個(gè)網(wǎng)站。他們可能使用單個(gè)數(shù)據(jù)庫(kù)確認(rèn)窗體身份驗(yàn)證登錄,然后為該用戶或用戶組打開與特定數(shù)據(jù)庫(kù)的連接。與身份驗(yàn)證數(shù)據(jù)庫(kù)的連接將建立池連接,供每個(gè)用戶使用。但是,每個(gè)數(shù)據(jù)庫(kù)的連接存在一個(gè)獨(dú)立的池,因此增加了與服務(wù)器的連接數(shù)。 這也會(huì)對(duì)應(yīng)用程序設(shè)計(jì)產(chǎn)生副作用。但是,可以通過(guò)一個(gè)相對(duì)簡(jiǎn)單的方式避免此副作用,而又不會(huì)影響連接 SQL Server 時(shí)的安全性。不是為每個(gè)用戶或組連接獨(dú)立的數(shù)據(jù)庫(kù),而是連接到服務(wù)器上的相同數(shù)據(jù)庫(kù),然后執(zhí)行 Transact-SQL USE 語(yǔ)句來(lái)切換為所需的數(shù)據(jù)庫(kù)。以下代碼段演示入如何創(chuàng)建與 master 數(shù)據(jù)庫(kù)的初始連接,然后切換到 databaseName 字符串變量中指定的所需數(shù)據(jù)庫(kù)。 Visual Basic
' Assumes that command is a valid SqlCommand object. Using connection As New SqlConnection( _ "Server=MSSQL1;uid=xxx;pwd=xxx;database=master") connection.Open() command.ExecuteNonQuery("USE " & databaseName) End Using C#
// Assumes that command is a SqlCommand object. using (SqlConnection connection = new SqlConnection( "Server=MSSQL1;uid=xxx;pwd=xxx;database=master")) { connection.Open(); command.ExecuteNonQuery("USE " + databaseName); } 應(yīng)用程序角色和連接池通過(guò)調(diào)用 sp_setapprole 系統(tǒng)存儲(chǔ)過(guò)程激活了 SQL Server 應(yīng)用程序角色之后,該連接的安全上下文無(wú)法重置。但是,如果啟用了池,連接將返回池,在重復(fù)使用池連接時(shí)會(huì)出錯(cuò)。 如果使用的是 SQL Server 應(yīng)用程序角色,我們建議您在連接字符串中為應(yīng)用程序禁用連接池。 |
|
|
來(lái)自: thy > 《數(shù)據(jù)庫(kù)》