1. 程式人生 > >超時時間已到.錯誤及Max Pool Size設定

超時時間已到.錯誤及Max Pool Size設定

遇到這個錯誤:

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

問題描述:我們獲取連線超過連線池最大值時產生如上異常。通常連線池最大值為100。當我們獲取連線超過最大值時,ADO.NET等待連線池返回連線而超時,這樣將丟擲如上異常
解決辦法:首先要做的是在我們使用連線後立即關閉連線。如果沒有關閉連線那麼連線將儲存到連線池中知道GC來銷燬。這種情況下你以為連線池沒有到達最大值但實際上連線池已經到達了最大值 其次我們可以通過連線字串中的
Max Pool Size = N;來動態擴大連線池中的連線最大數量。

說明:

也就是在connectionString中如果未指定max pool size

的值,則max pool size=100,當訪問人員同時連線資料庫的數量為101人時,則會出現上面的錯誤。

當我們設定為:

"Server=(local); Integrated Security=SSPI; Database=Northwind; Max Pool Size=512; Min Pool Size=5"  時。則訪問人員同時連線資料庫的數量為513時,就會出現上面的錯誤。

-Connection Pool 是什麼呢 ? 每當程式需要讀寫資料庫的時候。Connection.Open()會使用ConnectionString連線到資料庫,資料庫會為程式建立 一個連線,並且保持開啟狀態,此後程式就可以使用T-SQL語句來查詢/更新資料庫。當執行到Connection.Close()後,資料庫就會關閉當 前的連線。很好,一切看上去都是如此有條不紊。 但是如果我的程式需要不定時的開啟和關閉連線,(比如說 ASP.Net 或是 Web Service ),例如當Http Request傳送到伺服器的時候、,我們需要開啟Connection 然後使用Select* from Table 返回一個DataTable/DataSet給客戶端/瀏覽器,然後關閉當前的Connection。那每次都Open/Close Connection 如此的頻繁操作對於整個系統無疑就成了一種浪費。 ADO.Net Team就給出了一個比較好地解決方法。將先前的Connection儲存起來,當下一次需要開啟連線的時候就將先前的Connection 交給下一個連線。這就是Connection Pool。


-Connection Pool
如何工作的? 首先當一個程式執行Connection.open()時候,ADO.net就需要判斷,此連線是否支援Connection Pool (Pooling 預設為True),如果指定為False, ADO.net就與資料庫之間建立一個連線(為了避免混淆,所有資料庫中的連線,都使用”連線”描述),然後返回給程式。

如果指定為 True,ADO.net就會根據ConnectString建立一個Connection Pool,然後向Connection Pool中填充Connection(所有.net程式中的連線,都使用”Connection”描述)。填充多少個Connection由Min Pool Size (預設為0)屬性來決定。例如如果指定為5,則ADO.net會一次與SQL資料庫之間開啟5個連線,然後將4個Connection,儲存在 Connection Pool中,1個Connection返回給程式。

當程式執行到Connection.close() 的時候。如果Pooling 為True,ADO.net 就把當前的Connection放到Connection Pool並且保持與資料庫之間的連線。

同時還會判斷Connection Lifetime(預設為0)屬性,0代表無限大,如果Connection存在的時間超過了Connection LifeTime,ADO.net就會關閉的Connection同時斷開與資料庫的連線,而不是重新儲存到Connection Pool中。

(這個設定主要用於群集的SQL 資料庫中,達到負載平衡的目的)。如果Pooling指定為False,則直接斷開與資料庫之間的連線。

然後當下一次Connection.Open() 執行的時候,ADO.Net就會判斷新的ConnectionString與之前儲存在Connection Pool中的Connection的connectionString是否一致。

(ADO.Net會將ConnectionString轉成二進位制流,所 以也就是說,新的ConnectionString與儲存在Connection Pool中的Connection的ConnectionString必須完全一致,即使多加了一個空格,或是修改了Connection String中某些屬性的次序都會讓ADO.Net認為這是一個新的連線,而從新建立一個新的連線。所以如果您使用的UserID,Password的認 證方式,修改了Password也會導致一個Connection,如果使用的是SQL的整合認證,就需要儲存兩個連線使用的是同一個)。

然後 ADO.net需要判斷當前的Connection Pool中是否有可以使用的Connection(沒有被其他程式所佔用),如果沒有的話,ADO.net就需要判斷ConnectionString設 置的Max Pool Size (預設為100),如果Connection Pool中的所有Connection沒有達到Max Pool Size,ADO.net則會再次連線資料庫,建立一個連線,然後將Connection返回給程式。

如果已經達到了 MaxPoolSize,ADO.net就不會再次建立任何新的連線,而是等待Connection Pool中被其他程式所佔用的Connection釋放,這個等待時間受SqlConnection.ConnectionTimeout(預設是15 秒)限制,也就是說如果時間超過了15秒,SqlConnection就會丟擲超時錯誤(所以有時候如果SqlConnection.open()方法拋 出超時錯誤,一個可能的原因就是沒有及時將之前的Connnection關閉,同時Connection Pool數量達到了MaxPoolSize。)

如果有可用的Connection,從Connection Pool 取出的Connection也不是直接就返回給程式,ADO.net還需要檢查ConnectionString的ConnectionReset屬性 (預設為True)是否需要對Connection 最一次reset。這是由於,之前從程式中返回的Connection可能已經被修改過,比如說使用 SqlConnection.ChangeDatabase method 修改當前的連線,此時返回的Connection可能就已經不是連線當前的Connection String指定的Initial Catalog資料庫了。所以需要reset一次當前的連線。但是由於所有的額外檢查都會增大ADO.net Connection Pool 對系統的開銷。