SQL Server Connection Pooling (ADO.NET)

目錄

原文鏈接

SQL Server 連接池 (ADO.NET)

池的創建和分配

添加連接

移除連接

清除池

事務支持

使用連接字符串關鍵字控制連接池

池碎片

因爲集成安全性產生的池碎片

因爲許多數據庫產生的池碎片

應用程序角色和連接池

應用程序角色替代項

請參閱


原文鏈接

https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling

SQL Server 連接池 (ADO.NET)

連接到數據庫服務器通常由幾個需要很長時間的步驟組成。 必須建立物理通道(例如套接字或命名管道),必須與服務器進行初次握手,必須分析連接字符串信息,必須由服務器對連接進行身份驗證,必須運行檢查以便在當前事務中登記,等等。

實際上,大多數應用程序僅使用一個或幾個不同的連接配置。 這意味着在執行應用程序期間,許多相同的連接將反覆地打開和關閉。若要打開連接的成本降至最低,ADO.NET 使用名爲優化技術連接池

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

只有配置相同的連接可以建立池連接。 ADO.NET 保留在同一時間,一個用於每個配置多個池。 在使用集成的安全性時,連接按照連接字符串以及 Windows 標識分到多個池中。 還根據連接是否已在事務中登記來建立池連接。 在使用 ChangePassword 時,SqlCredential 實例影響連接池。 SqlCredential 的不同實例將使用不同的連接池,即使用戶 ID 和密碼相,也是如此。

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

 備註

啓用連接池後,如果發生超時錯誤或其他登錄錯誤,則將引發異常,並且在接下來的五秒內進行的後續連接嘗試將失敗,此段時間稱爲“阻塞期”。 如果應用程序嘗試在阻塞期內進行連接,則將再次引發第一個異常。 阻塞期結束後的後續失敗將導致新的阻塞期,該阻塞期的持續時間是上一個阻塞期的兩倍,最長爲一分鐘。

池的創建和分配

在初次打開連接時,將根據完全匹配算法創建連接池,該算法將池與連接中的連接字符串關聯。 每個連接池都與一個不同的連接字符串相關聯。 打開新連接時,如果連接字符串並非與現有池完全匹配,將創建一個新池。 按進程、應用程序域、連接字符串以及 Windows 標識(在使用集成的安全性時)來建立池連接。 連接字符串還必須是完全匹配的;按不同順序爲同一連接提供的關鍵字將分到單獨的池中。

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

C#複製

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 被卸載並且進程結束之前,連接池不會被破壞。 非活動或空池的維護只需要最少的系統開銷。

 備註

當出現故障轉移等錯誤時,會自動清除池。

添加連接

連接池是爲每個唯一的連接字符串創建的。 當創建一個池後,將創建多個連接對象並將其添加到該池中,以滿足最小池大小的需求。連接根據需要添加到池中,但是不能超過指定的最大池大小(默認值爲 100)。 連接在關閉或斷開時釋放回池中。

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

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

 注意

我們強烈建議您在使用完連接時一定要關閉連接,以便連接可以返回池。 你可以使用任一CloseDispose方法的Connection對象,或通過打開內的所有連接using語句在 C# 中,或Using在 Visual Basic 中的語句。 不是顯式關閉的連接可能不會添加或返回到池中。 有關詳細信息,請參閱using 語句如何:釋放系統資源適用於 Visual Basic。

 備註

不要在類的 Close 方法中對 DisposeConnection 或任何其他託管對象調用 DataReader 或 Finalize。 在終結器中,僅釋放類直接擁有的非託管資源。 如果類不擁有任何非託管資源,則不要在類定義中包含 Finalize 方法。 有關詳細信息,請參閱垃圾回收

有關打開和關閉連接與關聯的事件的詳細信息,請參閱Audit Login Event ClassAudit Logout Event Class SQL Server 文檔中。

移除連接

如果空閒時間達到大約 4-8 分鐘,或池進程檢測到與服務器的連接已斷開,連接池進程會將該連接從池中移除。 注意,只有在嘗試與服務器進行通信之後才能檢測到斷開的連接。 如果發現某連接不再連接到服務器,則會將其標記爲無效。 無效連接只有在關閉或重新建立後,纔會從連接池中移除。

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

清除池

ADO.NET 2.0 引入了兩個新方法來清除池:ClearAllPoolsClearPool。 ClearAllPools 清除指定提供程序的連接池,ClearPool 清除與特定連接關聯的連接池。 如果在調用時連接正在使用,將對它們進行相應的標記。 連接關閉時,將被丟棄,而不是返回池中。

事務支持

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

當連接關閉時,它將被釋放回池中,並根據其事務上下文放入相應的子部分。 因此,即使分佈式事務仍然掛起,仍可以關閉該連接而不會生成錯誤。 這樣,你就可以在之後提交或中止分佈式事務。

使用連接字符串關鍵字控制連接池

ConnectionString 對象的 SqlConnection 屬性支持連接字符串鍵/值對,可以用於調整連接池邏輯的行爲。 有關詳細信息,請參閱 ConnectionString

池碎片

池碎片是許多 Web 應用程序中的一個常見問題,應用程序可能會創建大量在進程退出後纔會釋放的池。 這樣,將打開大量的連接,佔用許多內存,從而導致性能降低。

因爲集成安全性產生的池碎片

連接根據連接字符串以及用戶標識來建立池連接。 因此,如果使用網站上的基本身份驗證或 Windows 身份驗證以及集成的安全登錄,每個用戶將獲得一個池。 儘管這樣可以提高單個用戶的後續數據庫請求的性能,但是該用戶無法利用其他用戶建立的連接。 這樣還使每個用戶至少產生一個與數據庫服務器的連接。 這對特定 Web 應用程序結構會產生副作用,因爲開發人員必須衡量安全性和審計要求。

因爲許多數據庫產生的池碎片

許多 Internet 服務提供商在一臺服務器上託管多個網站。 他們可能使用單個數據庫確認窗體身份驗證登錄,然後爲該用戶或用戶組打開與特定數據庫的連接。 與身份驗證數據庫的連接將建立池連接,供每個用戶使用。 但是,每個數據庫的連接存在一個獨立的池,這會增加與服務器的連接數。

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

C#複製

// 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();  
  }  

應用程序角色和連接池

通過調用 sp_setapprole 系統存儲過程激活了 SQL Server 應用程序角色之後,該連接的安全上下文無法重置。 但是,如果啓用了池,連接將返回池,在重複使用池連接時會出錯。 有關詳細信息,請參閱知識庫文章"通過使用 OLE DB 資源池的 SQL 應用程序角色錯誤。"

應用程序角色替代項

建議您利用可以使用的安全機制,而不使用應用程序角色。 有關詳細信息,請參閱SQL Server 中創建應用程序角色

請參閱

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章