天天看點

SQL Server 連接配接池 (ADO.NET)

連接配接到資料庫伺服器通常由幾個需要很長時間的步驟組成。必須建立實體通道(例如套接字或命名管道),必須與伺服器進行初次握手,必須分析連接配接字元串資訊,必須由伺服器對連接配接進行身份驗證,必須運作檢查以便在目前事務中登記,等等。

實際上,大多數應用程式僅使用一個或幾個不同的連接配接配置。這意味着在執行應用程式期間,許多相同的連接配接将反複地打開和關閉。為了使打開連接配接花費的系統開銷最小,ADO.NET 使用稱為連接配接池的優化方法。

連接配接池使新連接配接必須打開的次數得以減少。池程序保持實體連接配接的所有權。通過為每個給定的連接配接配置保留一組活動連接配接來管理連接配接。每當使用者在連接配接上調用 Open 時,池程序就會查找池中可用的連接配接。如果某個池連接配接可用,會将該連接配接傳回給調用者,而不是打開新連接配接。應用程式在該連接配接上調用 Close 時,池程序會将連接配接傳回到活動連接配接池集中,而不是關閉連接配接。連接配接傳回到池中之後,即可在下一個 Open 調用中重複使用。

隻有配置相同的連接配接可以建立池連接配接。ADO.NET 同時保留多個池,每種配置各一個。在使用內建的安全性時,連接配接按照連接配接字元串以及 Windows 辨別分到多個池中。還根據連接配接是否已在事務中登記來建立池連接配接。

池連接配接可以顯著提高應用程式的性能和可縮放性。預設情況下,在 ADO.NET 中啟用連接配接池。除非顯式禁用,否則,在應用程式中打開和關閉連接配接時,池程序會對連接配接進行優化。還可以提供幾個連接配接字元串修飾符來控制連接配接池的行為。有關更多資訊,請參見本主題後面的“使用連接配接字元串關鍵字控制連接配接池”。

SQL Server 連接配接池 (ADO.NET)

 池的建立和配置設定

在初次打開連接配接時,将根據完全比對算法建立連接配接池,該算法将池與連接配接中的連接配接字元串關聯。每個連接配接池都與一個不同的連接配接字元串相關聯。打開新連接配接時,如果連接配接字元串并非與現有池完全比對,将建立一個新池。按程序、應用程式域、連接配接字元串以及 Windows 辨別(在使用內建的安全性時)來建立池連接配接。連接配接字元串還必須是完全比對的;按不同順序為同一連接配接提供的關鍵字将分到單獨的池中。

在以下 C# 示例中建立了三個新的 SqlConnection 對象,但是管理時隻需要兩個連接配接池。注意,根據為 Initial Catalog 配置設定的值,第一個和第二個連接配接字元串有所不同。

SQL Server 連接配接池 (ADO.NET)
複制代碼
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 被解除安裝并且程序結束之前,連接配接池不會被破壞。非活動或空池的維護隻需要最少的系統開銷。

SQL Server 連接配接池 (ADO.NET)
說明:
當出現故障轉移等錯誤時,會自動清除池。
SQL Server 連接配接池 (ADO.NET)

 添加連接配接

連接配接池是為每個唯一的連接配接字元串建立的。當建立一個池後,将建立多個連接配接對象并将其添加到該池中,以滿足最小池大小的要求。連接配接根據需要添加到池中,但是不能超過指定的最大池大小(預設值為 100)。連接配接在關閉或斷開時釋放回池中。

在請求 SqlConnection 對象時,如果存在可用的連接配接,将從池中擷取該對象。連接配接要可用,必須未使用,具有比對的事務上下文或未與任何事務上下文關聯,并且具有與伺服器的有效連結。

連接配接池程序通過在連接配接釋放回池中時重新配置設定連接配接,來滿足這些連接配接請求。如果已達到最大池大小且不存在可用的連接配接,則該請求将會排隊。然後,池程序嘗試重建立立任何連接配接,直到到達逾時時間(預設值為 15 秒)。如果池程序在連接配接逾時之前無法滿足請求,将引發異常。

SQL Server 連接配接池 (ADO.NET)
警告:
我們強烈建議您在使用完連接配接時一定要關閉連接配接,以便連接配接可以傳回池。要關閉連接配接,可以使用 Connection 對象的 Close 或 Dispose 方法,也可以通過在 C# 的 using 語句中或 Visual Basic 的 Using 語句中打開所有連接配接。不是顯式關閉的連接配接可能不會添加或傳回到池中。有關更多資訊,請參見using 語句(C# 參考)或 Visual Basic 的如何:釋放系統資源。
SQL Server 連接配接池 (ADO.NET)
說明:
不要在類的 Finalize 方法中對 Connection、DataReader 或任何其他托管對象調用 Close 或 Dispose。在終結器中,僅釋放類直接擁有的非托管資源。如果類不擁有任何非托管資源,則不要在類定義中包含 Finalize 方法。有關更多資訊,請參見垃圾回收。
SQL Server 連接配接池 (ADO.NET)
說明:
從連接配接池中提取連接配接或連接配接傳回連接配接池時,伺服器不會引發登入和登出事件。這是因為連接配接傳回連接配接池時實際上沒有關閉。有關更多資訊,請參閱“SQL Server 聯機叢書”中的 Audit Login 事件類和 Audit Logout 事件類。
SQL Server 連接配接池 (ADO.NET)

 移除連接配接

如果連接配接長時間空閑,或池程序檢測到與伺服器的連接配接已斷開,連接配接池程序會将該連接配接從池中移除。注意,隻有在嘗試與伺服器進行通信之後才能檢測到斷開的連接配接。如果發現某連接配接不再連接配接到伺服器,則會将其标記為無效。無效連接配接隻有在關閉或重建立立後,才會從連接配接池中移除。

如果存在一個與已消失的伺服器的連接配接,即使連接配接池程序尚未檢測到斷開的連接配接,也可以從池中取出此連接配接并将連接配接标記為無效。這種情況是因為檢查連接配接是否仍有效的系統開銷将造成與伺服器的另一次往返,進而抵消了池程序的優勢。發生此情況時,初次嘗試使用該連接配接将檢測連接配接是否曾斷開,并引發異常。

SQL Server 連接配接池 (ADO.NET)

 清除池

ADO.NET 2.0 引入了兩種新的方法來清除池:ClearAllPools 和 ClearPool。ClearAllPools 将清除給定提供程式的連接配接池,而 ClearPool 将清除與特定連接配接相關聯的連接配接池。如果在調用時連接配接正在使用,将對它們進行相應的标記。連接配接關閉時,将被丢棄,而不是傳回池中。

SQL Server 連接配接池 (ADO.NET)

 事務支援

連接配接是根據事務上下文來從池中取出并進行配置設定的。除非在連接配接字元串中指定了 Enlist=false,否則連接配接池将確定連接配接在 Current 上下文中登記。如果連接配接使用登記的 System.Transactions 事務關閉并傳回到池中,連接配接将保留在池中,以便使用相同 System.Transactions 事務對該連接配接池的下一次請求将傳回相同的連接配接(如果可用)。如果發出這樣的請求,而沒有可用的池連接配接,則會從池的非事務性部分取出一個連接配接并登記。如果在池的每個區域都沒有可用的連接配接,則會建立一個新的連接配接并登記。

當連接配接關閉時,它将被釋放回池中,并根據其事務上下文放入相應的子部分。是以,即使分布式事務仍然挂起,仍可以關閉該連接配接而不會生成錯誤。這樣,您就可以在之後送出或中止分布式事務。

SQL Server 連接配接池 (ADO.NET)

 使用連接配接字元串關鍵字控制連接配接池

SqlConnection 對象的 ConnectionString 屬性支援連接配接字元串鍵/值對,可以用于調整連接配接池邏輯的行為。有關更多資訊,請參見 ConnectionString。

SQL Server 連接配接池 (ADO.NET)

 池碎片

池碎片是許多 Web 應用程式中的一個常見問題,應用程式可能會建立大量在程序退出後才會釋放的池。這樣,将打開大量的連接配接,占用許多記憶體,進而導緻性能降低。

因為內建安全性産生的池碎片

連接配接根據連接配接字元串以及使用者辨別來建立池連接配接。是以,如果使用網站上的基本身份驗證或 Windows 身份驗證以及內建的安全登入,每個使用者将獲得一個池。盡管這樣可以提高單個使用者的後續資料庫請求的性能,但是該使用者無法利用其他使用者建立的連接配接。這樣還使每個使用者至少産生一個與資料庫伺服器的連接配接。這對特定 Web 應用程式結構會産生副作用,因為開發人員必須衡量安全性和審計要求。

因為許多資料庫産生的池碎片

許多 Internet 服務提供商在一台伺服器上托管多個網站。他們可能使用單個資料庫确認窗體身份驗證登入,然後為該使用者或使用者組打開與特定資料庫的連接配接。與身份驗證資料庫的連接配接将建立池連接配接,供每個使用者使用。但是,每個資料庫的連接配接存在一個獨立的池,這會增加與伺服器的連接配接數。

這也會對應用程式設計産生副作用。但是,可以通過一個相對簡單的方式避免此副作用,而又不會影響連接配接 SQL Server 時的安全性。不是為每個使用者或組連接配接獨立的資料庫,而是連接配接到伺服器上的相同資料庫,然後執行 Transact-SQL USE 語句來切換為所需的資料庫。以下代碼段示範如何建立與 master 資料庫的初始連接配接,然後切換到 databaseName 字元串變量中指定的所需資料庫。

Visual Basic
SQL Server 連接配接池 (ADO.NET)
複制代碼
' Assumes that command is a valid SqlCommand object and that
' connectionString connects to master.
    command.Text = "USE DatabaseName"
Using connection As New SqlConnection(connectionString)
    connection.Open()
    command.ExecuteNonQuery()
End Using
      
C#
SQL Server 連接配接池 (ADO.NET)
複制代碼
// 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 連接配接池 (ADO.NET)

 應用程式角色和連接配接池

通過調用 sp_setapprole 系統存儲過程激活了 SQL Server 應用程式角色之後,該連接配接的安全上下文無法重置。但是,如果啟用了池,連接配接将傳回池,在重複使用池連接配接時會出錯。有關更多資訊,請參見知識庫文章“SQL application role errors with OLE DB resource pooling”(OLE DB 資源池出現 SQL 應用程式角色錯誤)。

應用程式角色替代項

如果您使用的是 SQL Server 2005,建議您使用可以替代應用程式角色的新安全機制。有關更多資訊,請參見在 SQL Server 中建立應用程式角色 (ADO.NET)。