連接到數據庫服務器通常由幾個需要很長時間的步驟組成。必須建立物理通道(例如套接字或命名管道),必須與服務器進行初次握手,必須分析連接字符串信息,必須由服務器對連接進行身份驗證,必須運行檢查以便在當前事務中登記,等等。
實際上,大多數應用程序僅使用一個或幾個不同的連接配置。這意味着在執行應用程序期間,許多相同的連接將反復地打開和關閉。為了使打開連接花費的系統開銷最小,ADO.NET 使用稱為連接池的優化方法。
連接池使新連接必須打開的次數得以減少。池進程保持物理連接的所有權。通過為每個給定的連接配置保留一組活動連接來管理連接。每當用戶在連接上調用 Open時,池進程就會查找池中可用的連接。如果某個池連接可用,會將該連接返回給調用者,而不是打開新連接。應用程序在該連接上調用 Close 時,池進程會將連接返回到活動連接池集中,而不是關閉連接。連接返回到池中之后,即可在下一個 Open 調用中重復使用。
只有配置相同的連接可以建立池連接。ADO.NET 同時保留多個池,每種配置各一個。在使用集成的安全性時,連接按照連接字符串以及 Windows 標識分到多個池中。還根據連接是否已在事務中登記來建立池連接。
連接池可以顯著提高應用程序的性能和可縮放性。默認情況下,在 ADO.NET 中啟用連接池。除非顯式禁用,否則,在應用程序中打開和關閉連接時,池進程會對連接進行優化。還可以提供幾個連接字符串修飾符來控制連接池的行為。有關更多信息,請參見本主題后面的“使用連接字符串關鍵字控制連接池”。
池的創建和分配
在以下 C# 示例中創建了三個新的 SqlConnection 對象,但是管理時只需要兩個連接池。 注意,根據為 Initial Catalog 分配的值,第一個和第二個連接字符串有所不同。
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 在連接字符串中未指定或指定為零,池中的連接將在一段時間不活動后關閉。但是,如果指定的 MinPoolSize 大於零,在 AppDomain 被卸載並且進程結束之前,連接池不會被破壞。非活動或空池的維護只需要最少的系統開銷。
注意:當出現故障轉移等錯誤時,會自動清除池。
添加鏈接
在請求 SqlConnection 對象時,如果存在可用的連接,將從池中獲取該對象。 連接要可用,必須未使用,具有匹配的事務上下文或未與任何事務上下文關聯,並且具有與服務器的有效鏈接。
連接池進程通過在連接釋放回池中時重新分配連接,來滿足這些連接請求。 如果已達到最大池大小且不存在可用的連接,則該請求將會排隊。 然后,池進程嘗試重新建立任何連接,直至到達超時時間(默認值為 15 秒)。 如果池進程在連接超時之前無法滿足請求,將引發異常。
注意:
[1] 建議在使用完連接時一定要關閉連接,以便連接可以返回池。 要關閉連接,可以使用 Connection 對象的 Close 或 Dispose 方法,也可以通過在 C# 的 using 語句中打開所有連接。 不是顯式關閉的連接可能不會添加或返回到池中。
[2] 不要在類的 Finalize 方法中對 Connection、DataReader 或任何其他托管對象調用 Close 或 Dispose。 在終結器中,僅釋放類直接擁有的非托管資源。 如果類不擁有任何非托管資源,則不要在類定義中包含 Finalize 方法。
[3] 從連接池中提取連接或連接返回連接池時,服務器不會引發登錄和注銷事件。 這是因為連接返回連接池時實際上沒有關閉。
移除連接
如果存在一個與已消失的服務器的連接,即使連接池進程尚未檢測到斷開的連接,也可以從池中取出此連接並將連接標記為無效。 這種情況是因為檢查連接是否仍有效的系統開銷將造成與服務器的另一次往返,從而抵消了池進程的優勢。 發生此情況時,初次嘗試使用該連接將檢測連接是否曾斷開,並引發異常。
清除池
ADO.NET 2.0 引入了兩種新的方法來清除池:ClearAllPools 和 ClearPool。 ClearAllPools 將清除給定提供程序的連接池,而 ClearPool 將清除與特定連接相關聯的連接池。 如果在調用時連接正在使用,將對它們進行相應的標記。 連接關閉時,將被丟棄,而不是返回池中。
事務支持
連接是根據事務上下文來從池中取出並進行分配的。 除非在連接字符串中指定了 Enlist=false,否則連接池將確保連接在 Current 上下文中登記。 如果連接使用登記的 System.Transactions 事務關閉並返回到池中,連接將保留在池中,以便使用相同 System.Transactions 事務對該連接池的下一次請求將返回相同的連接(如果可用)。 如果發出這樣的請求,而沒有可用的池連接,則會從池的非事務性部分取出一個連接並登記。 如果在池的每個區域都沒有可用的連接,則會創建一個新的連接並登記。
當連接關閉時,它將被釋放回池中,並根據其事務上下文放入相應的子部分。 因此,即使分布式事務仍然掛起,仍可以關閉該連接而不會生成錯誤。 這樣,您就可以在之后提交或中止分布式事務。
使用連接字符串關鍵字控制連接池
SqlConnection 對象的 ConnectionString 屬性支持連接字符串鍵/值對,可以用於調整連接池邏輯的行為。
池碎片
1、因為集成安全性產生的池碎片
連接根據連接字符串以及用戶標識來建立池連接。 因此,如果使用網站上的基本身份驗證或 Windows 身份驗證以及集成的安全登錄,每個用戶將獲得一個池。 盡管這樣可以提高單個用戶的后續數據庫請求的性能,但是該用戶無法利用其他用戶建立的連接。 這樣還使每個用戶至少產生一個與數據庫服務器的連接。 這對特定 Web 應用程序結構會產生副作用,因為開發人員必須衡量安全性和審計要求。
2、因為許多數據庫產生的池碎片
許多 Internet 服務提供商在一台服務器上托管多個網站。 他們可能使用單個數據庫確認窗體身份驗證登錄,然后為該用戶或用戶組打開與特定數據庫的連接。 與身份驗證數據庫的連接將建立池連接,供每個用戶使用。 但是,每個數據庫的連接存在一個獨立的池,這會增加與服務器的連接數。
這也會對應用程序設計產生副作用。 但是,可以通過一個相對簡單的方式避免此副作用,而又不會影響連接 SQL Server 時的安全性。 不是為每個用戶或組連接獨立的數據庫,而是連接到服務器上的相同數據庫,然后執行 Transact-SQL USE 語句來切換為所需的數據庫。 以下代碼段演示如何創建與 master 數據庫的初始連接,然后切換到 databaseName 字符串變量中指定的所需數據庫。
// Assumes that command is a SqlCommand object and that // connectionString connects to master. command.Text = "USE DatabaseName"; using (SqlConnection connection = new SqlConnection( connectionString)) { connection.Open(); command.ExecuteNonQuery(); }
應用程序角色和連接池
應用程序角色替代項
如果您使用的是 SQL Server 2005,建議您使用可以替代應用程序角色的新安全機制。
下表列出了 ConnectionString 中的關鍵字值的有效名稱。
| 關鍵字 |
默認值 |
說明 |
|---|---|---|
| Addr |
不可用 |
“數據源”的同義詞。 |
| 地址 |
不可用 |
“數據源”的同義詞。 |
| App |
不可用 |
“應用程序名稱”的同義詞。 |
| Application Name |
不可用 |
應用程序的名稱,或者“.Net SqlClient Data Provider”(如果不提供應用程序名稱)。 應用程序名稱可以有 128 個字符或更少。 |
| Asynchronous Processing - 或 - Async |
'false' |
如果設置為 true,則啟用異步操作支持。 可識別的值為 true、false、yes 和 no。 |
| AttachDBFilename - 或 - 擴展屬性 - 或 - Initial File Name |
不可用 |
主數據庫文件的名稱,包括可連接數據庫的完整路徑名。 只有具有 .mdf 擴展名的主數據文件才支持 AttachDBFilename。 如果在連接字符串中指定了 AttachDBFileName 鍵的值,則附加數據庫,且數據庫成為連接的默認數據庫。 如果不指定此鍵,且如果數據庫是以前附加的,則不會重新附加該數據庫將。 之前連接的數據庫將用作連接的默認數據庫。 如果連同 AttachDBFileName 鍵指定此鍵,則將把該鍵的值用作別名。 但是,如果該名稱已在另一個附加數據庫中使用,則此連接將失敗。 該路經可以是絕對路徑,也可以是相對路徑,這取決於是否使用 DataDirectory 替換字符串。 如果使用 DataDirectory,則對應的數據庫文件必須存在於替換字符串指向的目錄的子目錄中。 注意
遠程服務器、HTTP 及 UNC 路徑名不受支持。
必須按照如下方式使用關鍵字“database”(或其別名之一)指定數據庫名稱: "AttachDbFileName=|DataDirectory|\data\YourDB.mdf;integrated security=true;database=YourDatabase" 如果數據文件所在的目錄中存在日志文件,並且在附加主數據文件時使用了“database”關鍵字,則會生成錯誤。 這種情況下,請移除日志文件。 附加了數據庫后,系統將根據物理路徑自動生成一個新的日志文件。 |
| Connection Lifetime - 或 - Load Balance Timeout |
0 |
當連接被返回到池時,將其創建時間與當前時間作比較,如果時間長度(以秒為單位)超出了由 Connection Lifetime 指定的值,該連接就會被銷毀。 這在聚集配置中很有用(用於強制執行運行中的服務器和剛置於聯機狀態的服務器之間的負載平衡)。 零 (0) 值將使池連接具有最大的連接超時。 |
| Connect Timeout - 或 - Connection Timeout - 或 - 超時 |
15 |
在終止嘗試並產生錯誤之前,等待與服務器的連接的時間長度(以秒為單位)。 有效值大於或等於 0 且小於或等於 2147483647 。 |
| Context Connection |
'false' |
如果應對 SQL Server 進行進程內連接,則為 true。 |
| Current Language - 或 - Language |
不可用 |
設置用於數據庫服務器的警告或錯誤消息的語言。 語言名稱可以有 128 個字符或更少。 |
| 數據源 - 或 - 服務器 - 或 - 地址 - 或 - Addr - 或 - Network Address |
不可用 |
要連接的 SQL Server 實例的名稱或網絡地址。 可以在服務器名稱之后指定端口號: server=tcp:servername, portnumber 指定本地實例時,始終使用 (local)。 若要強制使用某個協議,請添加下列前綴之一: np:(local), tcp:(local), lpc:(local) 數據源必須使用 TCP 格式或命名的管道格式。 TCP 格式如下所示:
TCP 格式必須以前綴 "tcp:" 開始,后面跟着數據庫實例,指其由主機名和實例名指定。 該主機名稱“必須”按以下一種方式指定:
實例名稱用於解析數據庫實例所承載的特定 TCP/IP 端口號。 另外,還允許直接指定 TCP/IP 端口號。 如果兩個實例名稱和端口號不存在,則使用默認的數據庫實例。 Named Pipes 格式如下所示:
命名管道格式必須以前綴"np:" 開始,后面跟着一個命名的管道名稱。 該主機名稱“必須”按以下一種方式指定:
管道名稱用於標識數據庫實例,.NET Framework 應用程序將連接至該數據庫實例。 如果 Network 鍵的值已指定,則前綴“tcp:”與“np:”不應指定。 注意
ADO.NET 2.0 不支持在 SQL Server 2000 或更低版本的共享內存上執行異步命令。但是,可以強制用 TCP 代替共享內存,方法是:向連接字符串中的服務器名稱添加“tcp:”前綴,或者使用“本地主機”。
|
| Encrypt |
'false' |
當該值為 true 時,如果服務器端安裝了證書,則 SQL Server 將對所有在客戶端和服務器之間傳送的數據使用 SSL 加密。 可識別的值為 true、false、yes 和 no。 |
| Enlist |
'true' |
true 表明 SQL Server 連接池程序在創建線程的當前事務上下文中自動登記連接。 |
| Failover Partner |
不可用 |
在其中配置數據庫鏡像的故障轉移合作伙伴服務器的名稱。 如果該鍵的值為 "",則 Initial Catalog 必須存在且值不能為 ""。 服務器名稱可為 128 個字符或更少。 如果您指定故障轉移合作伙伴,且未配置數據庫鏡像的故障轉移合作伙伴,而且(用服務器關鍵字指定的)主服務器不可用, 則連接將失敗。 如果您指定故障轉移合作伙伴,且未配置數據庫鏡像的主服務器,那么主服務器可用時,(用服務器關鍵字指定)的主服務器的連接會成功。 .NET Framework 1.0 或 1.1 版不支持 Failover Partner 關鍵字。 |
| Initial Catalog - 或 - 數據庫 |
不可用 |
數據庫的名稱。 數據庫名稱可以有 128 個字符或更少。 |
| Integrated Security - 或 - Trusted_Connection |
'false' |
當為 false 時,將在連接中指定用戶 ID 和密碼。 當為 true 時,將使用當前的 Windows 帳戶憑據進行身份驗證。 可識別的值為 true、false、yes、no 以及與 true 等效的 sspi(強烈推薦)。 如果指定了用戶 ID 和密碼,且集成安全性設置為 true,則用戶 ID 和密碼將被忽略,並使用集成安全性。 |
| Min Pool Size |
0 |
池中允許的最大連接數。 有效值大於或等於 0。 此字段中的零 (0) 是指最初並未打開任何最小連接。 大於最大池大小的值將生成錯誤。 |
| Max Pool Size |
100 |
池中允許的最大連接數。 有效值大於或等於 1。 小於最小池大小的值將生成錯誤。 |
| MultipleActiveResultSets |
'false' |
如果為 true,則應用程序可以維護多活動結果集 (MARS)。 如果為 false,則應用程序必須在執行該連接上的任何其他批處理之前處理或取消一個批處理中的多個結果集。 可識別的值為 true 和 false。 .NET Framework 1.0 或 1.1 版不支持該關鍵字。 |
| Network Library - 或 - 網絡 - 或 - Net |
不可用 |
用於建立與 SQL Server 實例的連接的網絡庫。 支持的值包括: dbnmpntw(命名管道) dbmsrpcn(多協議,Windows RPC) dbmsadsn (Apple Talk) dbmsgnet (VIA) dbmslpcn(共享內存) dbmsspxn (IPX/SPX) dbmssocn (TCP/IP) Dbmsvinn (Banyan Vines) 相應的網絡 DLL 必須安裝在要連接的系統上。 如果不指定網絡而使用一個本地服務器(比如“.”或“(local)”),則使用共享內存。在此示例中,網絡庫為 Win32 Winsock TCP/IP (dbmssocn),使用的端口為 1433。 Network Library=dbmssocn;Data Source=000.000.000.000,1433;
|
| Packet Size |
8192 |
用來與 SQL Server 的實例進行通信的網絡數據包的大小,以字節為單位。 包大小可以大於或等於 512 並小於或等於 32767。 |
| 密碼 - 或 - PWD |
不可用 |
SQL Server 帳戶登錄的密碼。 建議不要使用。 為保持高安全級別,我們強烈建議您使用 Integrated Security 或Trusted_Connection 關鍵字。 密碼必須為 128 個字符或更少。 |
| Persist Security Info - 或 - PersistSecurityInfo |
'false' |
當該值設置為 false 或 no(強烈推薦)時,如果連接是打開的或者一直處於打開狀態,那么安全敏感信息(如密碼)將不會作為連接的一部分返回。 重置連接字符串將重置包括密碼在內的所有連接字符串值。 可識別的值為 true、false、yes 和 no。 |
| Pooling |
'true' |
當此密鑰的值設置為 true 時,在通過應用程序進行關閉時任何新創建的連接都被將添加到池。 在下一次嘗試打開相同的連接時,該連接將會從池中被繪制。 如果連接具有相同的連接字符串,則將它們視為相同。 不同連接具有不同連接字符串。 此密鑰的值可以為 "true"、"false"、"yes" 或 "no"。 |
| 復制 |
'false' |
如果使用連接來支持復制,則為 true。 |
| Transaction Binding |
Implicit Unbind |
控制與登記的 System.Transactions 事務關聯的連接。 可能的值包括: Transaction Binding=Implicit Unbind; Transaction Binding=Explicit Unbind; Implicit Unbind 可使連接在事務結束時從事務中分離。 分離后,連接上的其他請求將以自動提交模式執行。 在事務處於活動狀態的情況下執行請求時,不會檢查 System.Transactions.Transaction.Current 屬性。 事務結束后,其他請求將以自動提交模式執行。 如果系統在最后一個命令完成之前結束該事務(在 Using 塊的范圍中),則它將引發 InvalidOperationException。 Explicit Unbind 可使連接保持連接到事務,直到連接關閉或調用顯式 SqlConnection.TransactionEnlist(null)。 從 .NET Framework 4 版 開始,對 Implicit Unbind 所做的更改將使得 Explicit Unbind 過時。 如果 Transaction.Current 不是登記的事務或登記的事務未處於活動狀態,則引發 InvalidOperationException。 |
| TrustServerCertificate |
'false' |
如果設置為 true,則使用 SSL 對通道進行加密,但不通過證書鏈對可信度進行驗證。 如果將 TrustServerCertificate 設置為 true並將 Encrypt 設置為 false,則不對通道進行加密。 可識別的值為 true、false、yes 和 no。 有關更多信息,請參見 連接字符串語法 (ADO.NET)。 |
| Type System Version |
不可用 |
指示應用程序期望的類型系統的字符串值。 可能的值包括: Type System Version=SQL Server 2000; Type System Version=SQL Server 2005; Type System Version=SQL Server 2008; Type System Version=Latest; 如果設置為 SQL Server 2000,將使用 SQL Server 2000 類型系統。 與 SQL Server 2005 實例連接時,執行下列轉換: XML 與 NTEXT UDT 到 VARBINARY VARCHAR(MAX)、NVARCHAR(MAX) 和 VARBINARY(MAX) 分別與 TEXT、NEXT 和 IMAGE。 如果設置為 SQL Server 2005,將使用 SQL Server 2005 類型系統。 對 ADO.NET 的當前版本不進行任何轉換。 如果設置為 Latest,將使用此客戶端-服務器對無法處理的最新版本。 這個最新版本將隨着客戶端和服務器組件的升級自動更新。 |
| 用戶 ID - 或 - UID - 或 -
|
不可用 |
SQL Server 登錄帳戶。 建議不要使用。 為保持高安全級別,我們強烈建議您使用 Integrated Security 或 Trusted_Connection關鍵字。 用戶 ID 所包含的字符數不能超過 128 個。 |
| User Instance |
'false' |
一個值,用於指示是否將連接從默認的 SQL Server Express 實例重定向到調用方帳戶下運行的運行時啟動的實例。 |
| Workstation ID - 或 - WSID |
本地計算機名稱 |
連接到 SQL Server 的工作站的名稱。 ID 所包含的字符數不能超過 128 個。 |
下表包含 ConnectionString 內連接池值的有效名稱。 有關更多信息,請參見 SQL Server 連接池 (ADO.NET)。
-
Connection Lifetime(或 Load Balance Timeout)
-
Enlist
-
Max Pool Size
-
Min Pool Size
-
Pooling
當設置需要布爾值的關鍵字或連接池值時,您可以使用“yes”代替“true”,用“no”代替“false”。 整數值表示為字符串。
注意:
SQL Server .NET Framework 數據提供程序使用它自己的協議與 SQL Server 進行通信。 因此,當連接到 SQL Server 時,它不支持 ODBC 數據源名稱 (DSN) 的使用,因為它不添加 ODBC 層。
用於 SQL Server 的 .NET Framework 數據提供程序不支持通用數據鏈接 (UDL) 文件。
在此版本中,在應用程序中根據用戶輸入構造連接字符串時(例如,從對話框中檢索用戶 ID 和密碼信息並將其追加到連接字符串時)應相當謹慎。 應用程序應確保用戶無法在這些值中嵌入其他連接字符串參數(例如,輸入“validpassword;database=somedb”作為密碼,以嘗試連接到其他數據庫)。 如果需要根據用戶輸入構造連接字符串,請使用新的 SqlConnectionStringBuilder,它可以驗證連接字符串,並有助於消除此問題。 有關更多信息,請參見 連接字符串生成器 (ADO.NET)。
示例
private static void OpenSqlConnection() { string connectionString = GetConnectionString(); using (SqlConnection connection = new SqlConnection()) { connection.ConnectionString = connectionString; connection.Open(); Console.WriteLine("State: {0}", connection.State); Console.WriteLine("ConnectionString: {0}", connection.ConnectionString); } } static private string GetConnectionString() { // To avoid storing the connection string in your code, // you can retrieve it from a configuration file. return "Data Source=MSSQL1;Initial Catalog=AdventureWorks;" + "Integrated Security=true;"; }
