連線池和連線數詳解

天府雲創發表於2018-04-04

解決方法:

超時時間已到。超時時間已到,但是尚未從池中獲取連線。出現這種情況可能是因為所有池連線均在使用,並且達到了最大池大小。 
說明: 執行當前 Web 請求期間,出現未處理的異常。請檢查堆疊跟蹤資訊,以瞭解有關該錯誤以及程式碼中導致錯誤的出處的詳細資訊。  

異常詳細資訊: System.InvalidOperationException: 超時時間已到。超時時間已到,但是尚未從池中獲取連線。出現這種情況可能是因為所有池連線均在使用,並且達到了最大池大小。

這是個老問題了!你就查兩點:   
  一、看所有open的連線是否都close了。   
  二、如果訪問量很大,加上Max Pool Size=512這一句,當然這是要以損失系統效能為代價的!   
  這樣以後一定可以解決你的問題!

  解決方案一

我 想原因可能是併發操作。DataReader是獨佔連線的,就是說你的程式可能設計上有問題。比如說最大連線設100,假設有100個人同時使用 DataReader正在讀取資料庫內容,那麼當第101人讀取的時候,連線池中的連線已經沒有了,就會出現上面的錯誤。DataReader是獨佔連線 的,每個DataReader都要佔用一個連線。當然這個情況是偶爾出現的,所以會很長時間出現一次,因為只有同時有超過連線池最大連線數量的併發操作才 會發生。而且你加大併發數量只能暫時緩解問題,如果你加大到200個併發連線,如果有201 人同時操作怎麼辦?你說了你使用Connection物件的Close()方法,這是不行的,因為Close()方法僅僅是關閉連線,但這個連線沒有釋 放,還是被這個物件佔用,要釋放必須使用Connection的Dispose()方法顯式釋放連線才可以,否則這個物件佔用的連線只能等到垃圾收集的情 況下才能被釋放。這種情況肯定會出現“超時時間已到”的錯誤。

解決方法:
  1 修改幾個關鍵頁面或訪問比較頻繁的資料庫訪問操作,使用DataAdapter和DataSet來獲取資料庫資料,不要使用DataReader。
  2 在訪問資料庫的頁面上使用資料快取,如果頁面的資料不是經常更新(幾分鐘更新一次)的話,使用Cache物件可以不用訪問資料庫而使用快取中的內容,那麼可以大大減少連線數量。
  3 修改程式碼,把使用Connection物件的地方都在Close()後面加上Dispose()呼叫。
  4 建議對資料庫操作進行大的修改,建立自己的資料庫操作代理類,繼承System.IDisposable介面,強迫釋放資源,這樣就不會出現連線數量不夠的問題了。

解決方案二

解決方法(*):WEB.config 裡面:在資料庫連線加 Max Pool Size = 512;server=local;uid=;pwd=;database=2004;Max Pool Size = 512;">一勞永逸。

解決方案三

估計是連線(Connection)物件沒有Close。倒是不必Dispose,而DataReader用完後應該關閉,但不關閉也沒問題,只是不關閉的話此連線物件就一直不能用,只要你最終關閉了連線物件就不會出問題。  
    
  連線物件在Open後的操作都放在try塊中,後面跟一個finally塊:conn.Close();


經常發生 “資料庫連線過多的錯誤” 這樣的錯誤,但是卻又不清楚當前的連線數為多少,大致的總結了幾種方法。
1.通過系統的“效能”來檢視:
開始->管理工具->效能(或者是執行裡面輸入 mmc)然後通過
[attach]52716[/attach]

新增計數器新增 SQL 的常用統計 然後在下面列出的專案裡面選擇使用者連線就可以時時查詢到資料庫的連線數了。
不過此方法的話需要有訪問那臺計算機的許可權,就是要通過windows賬戶登陸進去才可以新增此計數器。
2.通過系統表來查詢:
[code]SELECT * FROM 
[Master].[dbo].[SYSPROCESSES] WHERE [DBID] 
IN 
(
   SELECT 
[DBID]
   FROM 
[Master].[dbo].[SYSDATABASES] 
   WHERE 
NAME='databaseName'
)
[/code]

databaseName 是需要檢視的資料庫,然後查詢出來的行數,就是當前的連線數。不過裡面還有一些別的狀態可以做參考用。

由上面的語句可以看出系統表獲取一些連線和活動資訊,主要介紹下面的兩個系統表:

(1)sprocesses

sysprocesses 表中儲存關於執行在 Microsoft® SQL Server™ 上的程式的資訊。這些程式可以是客戶端程式或系統程式。sysprocesses 只儲存在 master 資料庫中。

(2)Sysperfinfo

包括一個 Microsoft® SQL Server™ 表示法的內部效能計數器,可通過 Windows NT 效能監視器顯示.

 

有人提議說為了獲取SQL Server的當前連線數:使用如下SQL:

SELECT COUNT(*) AS CONNECTIONS FROM master..sysprocesses

個人認為這樣不對,看看.sysprocesses的login_time列就可看出.


另外一個方面是程式不能和連線相提並論,他們是一對一的關係嗎,也就是說一個程式就是一個連線?一個連線應該有多個程式的,所以連線和程式之間的關係應該是1:n的.


因為sysprocesses列出的程式包含了系統程式和使用者程式,為了得到使用者連線,可以使用如下SQL:

SELECT cntr_value AS User_Connections FROM master..sysperfinfo as p
WHERE p.object_name = 'SQLServer:General Statistics' And p.counter_name = 'User Connections'

個人還是認為不對,因為它是一個計數器,可能會累加的.

還有一種方案是利用如下SQL:

select connectnum=count(distinct net_address)-1 from master..sysprocesses

理由是net_address是訪問者機器的網路卡值,這個總該是唯一的吧.但是看起來得到的是所有時間內的連線數.

希望大家可以給出自己的解決方案.這個問題解決了,相信會有很大的用途.


3.通過系統過程來查詢:
[url=http://search.microsoft.com/default.asp?so=RECCNT&siteid=us%2Fdev&p=1&nq=NEW&qu=SP_WHO&IntlSearch=&boolean=PHRASE&ig=01&i=09&i=99]SP_WHO[/url] 'loginName'
loginName 是當然登陸Sql的使用者名稱,一般程式裡面都會使用一個username來登陸SQL這樣通過這個使用者名稱就能檢視到此使用者名稱登陸之後佔用的連線了。
如果不寫loginName,那麼返回的就是所有的連線。

sp_who提供icrosoft® SQL Server™ 使用者和程式的資訊。可以篩選返回的資訊,以便只返回那些不是空閒的程式。

列出所有活動的使用者:SP_WHO ‘active’

列出某個特定使用者的資訊:SP_WHO ‘sa’

4、系統變數

@@CONNECTIONS 返回自上次啟動 Microsoft® SQL Server™ 以來連線或試圖連線的次數。

@@MAX_CONNECTIONS 返回 Microsoft® SQL Server™ 上允許的同時使用者連線的最大數。返回的數不必為當前配置的數值


***************連線池和連線數詳解**********

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

實際上,大多數應用程式僅使用一個或幾個不同的連線配置。 這意味著在執行應用程式期間,許多相同的連線將反覆地開啟和關閉。 為了使開啟的連線成本最低,ADO.NET 使用稱為連線池的優化方法。

連線池減少新連線需要開啟的次數。 池程式保持物理連線的所有權。 通過為每個給定的連線配置保留一組活動連線來管理連線。 只要使用者在連線上呼叫 Open,池程式就會檢查池中是否有可用的連線。 如果某個池連線可用,會將該連線返回給呼叫者,而不是開啟新連線。 應用程式對該連線呼叫 Close 時,池程式會將連線返回到活動連線池集中,而不是真正關閉連線。 連線返回到池中之後,即可在下一個 Open 呼叫中重複使用。

只有配置相同的連線可以建立池連線。 ADO.net 同時保留多個池,每個配置一個池。 連線由連線字串以及 Windows 標識(在使用整合的安全性時)分為多個池。 還根據連線是否已在事務中登記來建立池連線。

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

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

在以下 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 被解除安裝並且程式結束之前,連線池不會被破壞。 非活動或空池的維護只需要最少的系統開銷。

注意:  
當出現故障轉移等錯誤時,會自動清除池。
 
新增連線
連線池是為每個唯一的連線字串建立的。 當建立一個池後,將建立多個連線物件並將其新增到該池中,以滿足最小池大小的要求。 連線根據需要新增到池中,但是不能超過指定的最大池大小(預設值為 100)。 連線在關閉或斷開時釋放回池中。  

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

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

警告:  
我們強烈建議您在使用完連線後總是將其關閉,以使連線返回到池中。要關閉連線,可以使用 Connection 物件的 Close 或 Dispose 方法,也可以通過在 C# 的 using 語句中或在 Visual Basic 的 Using 語句中開啟所有連線。 不是顯式關閉的連線可能不會新增或返回到池中。 有關更多資訊,請參見 Visual Basic 的using Statement (C# Programmer's Reference)或How to: Dispose of a System Resource。
 
注意:  
不要在類的 Finalize 方法中對 Connection、DataReader 或任何其他託管物件呼叫 Close 或 Dispose。 在終結器中,僅釋放類直接擁有的非託管資源。 如果類不擁有任何非託管資源,則不要在類定義中包含 Finalize 方法。 有關更多資訊,請參見Garbage Collection。
 
移除連線
如果連線長時間空閒,或池程式檢測到與伺服器的連線已斷開,連線池程式會將該連線從池中移除。 注意,只有在嘗試與伺服器進行通訊之後才能檢測到斷開的連線。 如果發現某連線不再連線到伺服器,則會將其標記為無效。 無效連線只有在關閉或重新建立後,才會從連線池中移除。

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

清除池
ADO.NET 2.0 引入了清除池的兩種新方法: ClearAllPools 和 ClearPool。 ClearAllPools 清除給定提供程式的連線池,ClearPool 清除與特定連線關聯的連線池。 如果在呼叫時連線正在使用,將進行相應的標記。 連線關閉時,將被丟棄,而不是返回池中。

事務支援
連線是根據事務上下文來從池中取出並進行分配的。 除非在連線字串中指定了 Enlist=false,否則,連線池將確保連線在 Current 上下文中登記。 當連線通過登記的 System.Transactions 事務關閉並返回到池中時,連線將被保留,以便下次使用同一 System.Transactions 事務請求該連線池時,可返回同一連線(如果該連線可用)。如果該連線不可用,則會開啟新連線。如果該事務沒有可用連線,在該連線開啟時,將自動註冊該連線。

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

使用連線字串關鍵字控制連線池
SqlConnection 物件的 ConnectionString 屬性支援連線字串鍵/值對,可以用於調整連線池邏輯的行為。 有關更多資訊,請參見 ConnectionString。

池碎片
池碎片是許多 Web 應用程式中的一個常見問題,應用程式可能會建立大量在程式退出後才會釋放的池。 這樣,將開啟大量的連線,佔用許多記憶體,從而影響效能。

因為整合安全性產生的池碎片
連線根據連線字串以及使用者標識來建立池連線。 因此,如果使用網站上的基本身份驗證或 Windows 身份驗證以及整合的安全登入,每個使用者將獲得一個池。 儘管這樣可以提高單個使用者的後續資料庫請求的效能,但是該使用者無法利用其他使用者建立的連線。 這樣還使每個使用者至少產生一個與資料庫伺服器的連線。 這對特定 Web 應用程式結構會產生副作用,因為開發人員需要衡量安全性和審計要求。

因為許多資料庫產生的池碎片
許多 Internet 服務提供商在一臺伺服器上託管多個網站。 他們可能使用單個資料庫確認窗體身份驗證登入,然後為該使用者或使用者組開啟與特定資料庫的連線。 與身份驗證資料庫的連線將建立池連線,供每個使用者使用。 但是,每個資料庫的連線存在一個獨立的池,因此增加了與伺服器的連線數。

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

Visual Basic 複製程式碼  
' 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# 複製程式碼  
// 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 應用程式角色之後,該連線的安全上下文無法重置。 但是,如果啟用了池,連線將返回池,在重複使用池連線時會出錯。 有關更多資訊,請參見知識庫文章“SQL application role errors with OLE DB resource pooling”(OLE DB 資源池出現 SQL 應用程式角色錯誤)。

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



如果您認為這篇文章還不錯或者有所收穫,您可以通過右邊的“打賞”功能 打賞我一杯咖啡【物質支援】,也可以點選文章下方“推薦”按鈕【精神支援】,您的“推薦或者轉載分享”將是我最大的寫作動力!

相關文章