1. 程式人生 > >關於資料庫連線池的簡單理解

關於資料庫連線池的簡單理解

資料庫連線池更多的是一個本地的概念。以前一直覺得,資料庫連線池是資料庫伺服器上的一個概念,在資料庫伺服器上有一個池,裡邊存放著很多的執行緒的資料庫連線。

最近在分析的時候,發現這是不正確的,或者說,這樣理解是不全面的。其實,連線池更多是一個執行C#程式碼的那個本地機器上的概念,當然資料庫伺服器端也有涉及,因為畢竟連線是雙方的,但是更多的這個是從連線的本地角度出發的。

下面以一個網站的例子來具體分析一下這個問題。現在有一個網站,裡邊有C#程式碼,通過程式碼訪問遠端的SQLServer資料庫,來獲取所有的銷售人員的資料。現在我們把網站部署到伺服器A上邊,資料庫存在伺服器B上邊。

假如我們不使用資料庫連線池,每次當有人開啟瀏覽器輸入網站,在

A伺服器上邊就有一個相應的執行緒來處理這個請求,那麼在這個執行緒中就會有一個從AB的資料庫連線的開啟與關閉。建立連線是一個費時的活動,每次都得花費0.05s~1s的時間,費時間只是一個方面,而且還要費資源,系統要分配記憶體資源。這個對於一次或幾次資料庫操作,或許感覺不出系統有多大的開銷。可是對於現在的web應用,尤其是大型電子商務網站,同時有幾百人甚至幾千人線上是很正常的事。在這種情況下,頻繁的進行資料庫連線操作勢必佔用很多的系統資源,網站的響應速度必定下降,嚴重的甚至會造成伺服器的崩潰。如果同時有1000人訪問,就會不斷的有資料庫連線、斷開操作。

所以,這時候的思想就是,C#程式碼在本地建立了一個連線,在建立這個連線的同時,那麼我們把這個連線儲存到一個公共的區域,讓每一個

web請求的執行緒都能訪問到這個區域。而且,當下一次有一個新的執行緒要訪問資料庫,直接使用這個已有的連線就好了。為了避免同時有多個web執行緒都要請求資料庫的時候,會出現資源的爭奪,執行緒池那個公共區域中我們可以設定多個連線,這樣就可以避免資源的爭奪與等待。

但是從資料庫伺服器的角度來講,它並不知道跟它建立連線的是一個單次的執行緒,還是資料庫連線池裡邊的連線。它只知道有個連線在跟它連著,而且在對方沒有發出斷開的請求時,它就一直連線著。(這裡可能說的不太準確,資料庫伺服器能夠知道建立的是普通連線還是連線池的連線,但是這些對於巨集觀角度來講都不重要,都是一個從遠端客戶端來的連線。)

現在的C#

語言或者說Java語言中,在類庫中對於這些連線池的封裝已經做得很細緻,甚至都不用程式設計師去寫額外的程式碼。這裡拿C#程式碼連線Oracle資料庫舉個例子。你要想使用C#連線遠端的Oracle資料庫,第一你需要在本機安裝ODP.NET這個叫做Provider的元件,第二你需要在C#程式碼中引入Oracle.DataAcess.dll這個類庫。

當你的C#程式碼在使用類庫中的類建立連線,並且使用Open方法開啟連線的時候,這時候連線池就會初始化並建立設定的最小連線數。這時候可能就是為什麼要你安裝那個Provider,因為一個簡單的資料庫連線背後還有跟多的內容要做,可能一個dll是無法完成這個複雜的內容的。所以安裝了Provider之後,在執行C#程式碼的時候,C#程式碼引入類庫中的方法的時候,會呼叫Provider中的一些小的應用程式或者說程式集去完成複雜的內容。

最近發現Oracle資料庫的一個問題,在這篇部落格。http://blog.csdn.net/sundacheng1989/article/details/52755867

下面解釋一下原因:

說到底,每次C#程式碼new一個連線的時候(我們假設程式運行了一段時間並且連線池中有足夠的連線存在),並且Open的時候,都是去從連線池中去拿一個現成的連線。在使用完連線時一定要關閉連線,以便連線可以返回池。要關閉連線使用Close(),這時候不是真正的關閉了,還是還給了連線池。Oracle那個問題的所在就是,C#整個程式(或者也有Provider的參與)維繫著一個連線池,這個連線池中有很多的連線,在連著Oracle的資料庫伺服器。

因為很長一段時間內,Oracle資料庫伺服器那端都沒有檢測到這些連線有活動,就把這些連線給關閉了。但是應用程式維繫的連線池並沒有覺察到,所以一天後當再次new一個連線,conn.Open的時候,應用程式還是從連線池中拿了一個,並不知道拿的這個已經關閉了,C#程式碼繼續進行著進一步的查詢操作,這時候發現連不上了,所以,就丟擲了這個異常。這時候可以通過禁用連線池來解決這個問題,但是效能上就不太好了。

在主流的C#或者Java中,你生成一個連線的時候,預設的都是用連線池維護的,除非你明確指明瞭不使用連線池(在配置檔案的連線字串中加入threadingPool=false),這時候才會是每一個執行緒都建立一個連線並且完事後銷燬這個連線。