數(shù)據(jù)庫連接池的基本原理
數(shù)據(jù)庫連接池負責分配、管理和釋放數(shù)據(jù)庫連接,它允許應用程序重復使用一個現(xiàn)有的數(shù)據(jù)庫連接,而再不是重新建立一個;釋放空閑時間超過***空閑時間的數(shù)據(jù)庫連接來避免因為沒有釋放數(shù)據(jù)庫連接而引起的數(shù)據(jù)庫連接遺漏。傳統(tǒng)的數(shù)據(jù)庫連接方式(指通過DriverManager和基本實現(xiàn)DataSource進行連接)中,一個數(shù)據(jù)庫連接對象均對應一個物理數(shù)據(jù)庫連接,數(shù)據(jù)庫連接的建立以及關(guān)閉對系統(tǒng)而言是耗費系統(tǒng)資源的操作,在多層結(jié)構(gòu)的應用程序環(huán)境中這種耗費資源的動作對系統(tǒng)的性能影響尤為明顯。
在多層結(jié)構(gòu)的應用程序中通過連接池(connection pooling)技術(shù)可以使系統(tǒng)的性能明顯得到提到,連接池意味著當應用程序需要調(diào)用一個數(shù)據(jù)庫連接的時,數(shù)據(jù)庫相關(guān)的接口通過返回一個通過重用數(shù)據(jù)庫連接來代替重新創(chuàng)建一個數(shù)據(jù)庫連接。通過這種方式,應用程序可以減少對數(shù)據(jù)庫連接操作,尤其在多層環(huán)境中多個客戶端可以通過共享少量的物理數(shù)據(jù)庫連接來滿足系統(tǒng)需求。通過連接池技術(shù)Java應用程序不僅可以提高系統(tǒng)性能同時也為系統(tǒng)提高了可測量性。
數(shù)據(jù)庫連接池是運行在后臺的而且應用程序的編碼沒有任何的影響。此中狀況存在的前提是應用程序必須通過DataSource對象(一個實現(xiàn)javax.sql.DataSource接口的實例)的方式代替原有通過DriverManager類來獲得數(shù)據(jù)庫連接的方式。一個實現(xiàn)javax.sql.DataSource接口的類可以支持也可以不支持數(shù)據(jù)庫連接池,但是兩者獲得數(shù)據(jù)庫連接的代碼基本是相同的。
代碼如下:
一個DataSource對象通常注冊在JNDI命名服務上,應用程序可以通過標準的方式獲得到注冊在JNDI服務上的DataSource對象。
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("jdbc/openbase");
如果當前DataSource不支持數(shù)據(jù)庫連接池,應用程序?qū)@得一個和物理數(shù)據(jù)庫連接對應的Connection對象。而如果當前的DataSource對象支持數(shù)據(jù)庫連接池,應用程序自動獲得重用的數(shù)據(jù)庫連接而不用創(chuàng)建新的數(shù)據(jù)庫連接。重用的數(shù)據(jù)庫連接和新建立連接的數(shù)據(jù)庫連接使用上沒有任何不同。應用程序可以通過重用的連接正常的訪問數(shù)據(jù)庫,進行訪問數(shù)據(jù)的操作,完成操作后應顯式的調(diào)用close()關(guān)閉數(shù)據(jù)庫連接。
Connection con = ds.getConnection("User", "Pwd");
相關(guān)數(shù)據(jù)庫的操作;
con.close();
當關(guān)閉數(shù)據(jù)連接后,當前使用的數(shù)據(jù)庫連接將不會被物理關(guān)閉,而是放回到數(shù)據(jù)庫連接池中進行重用。
JDBC3.0規(guī)范中數(shù)據(jù)庫連接池框架
JDBC3.0規(guī)范中通過提供了一個支持數(shù)據(jù)庫連接池的框架,這個框架僅僅規(guī)定了如何支持連接池的實現(xiàn),而連接池的具體實現(xiàn)JDBC 3.0規(guī)范并沒有做相關(guān)的規(guī)定。通過這個框架可以讓不同角色的開發(fā)人員共同實現(xiàn)數(shù)據(jù)庫連接池。
通過JDBC3.0規(guī)范可以知道具體數(shù)據(jù)庫連接池的實現(xiàn)可以分為JDBC Driver級和Application Server級。在JDBC Driver級的實現(xiàn)中任何相關(guān)的工作均由特定數(shù)據(jù)庫廠商的JDBC Drvier的開發(fā)人員來具體實現(xiàn),即JDBC Driver既需要提供對數(shù)據(jù)庫連接池的支持同時也必須對數(shù)據(jù)庫連接池進行具體實現(xiàn)。而在Application Server級中數(shù)據(jù)庫連接池的實現(xiàn)中特定數(shù)據(jù)庫廠商的JDBC Driver開發(fā)人員和Application Server開發(fā)人員來共同實現(xiàn)數(shù)據(jù)庫連接池的實現(xiàn)(但是現(xiàn)在大多數(shù)Application Server廠商實現(xiàn)的連接池的機制和規(guī)范中提到有差異),其中特定數(shù)據(jù)庫廠商的JDBC Driver提供數(shù)據(jù)庫連接池的支持而特定的Application Server廠商提供數(shù)據(jù)庫連接池的具體實現(xiàn)。
JDBC3.0規(guī)范規(guī)定了如下的類和接口來支持數(shù)據(jù)庫連接池的實現(xiàn)。
javax.sql.ConnectionEvent
javax.sql.ConnectionPoolDataSource
javax.sql.PooledConnection
javax.sql.ConnectionEventListener
其中除javax.sql.ConnectionEvent是類,其它的均為接口。
通過此圖可以大概的了解相關(guān)接口在一個典型的三層環(huán)境中應用程序的位置。
數(shù)據(jù)庫連接池實現(xiàn)層次中,由特定數(shù)據(jù)庫廠商的JDBC Driver開發(fā)人員提供連接池支持,而特定Application Server提供連接池實現(xiàn)的情況比較復雜,其它的實現(xiàn)層次均可視為其簡化情況的一種。下面將針對這種情況進行說明。
在這個框架主要有兩個用戶角色存在,它們分別是:
特定數(shù)據(jù)庫廠商的JDBC Driver開發(fā)人員,之后將簡稱為Driver Vendor
特定Application Server中連接池開發(fā)人員,之后將簡稱為Pooling Vendor
下面對幾個關(guān)鍵模塊進行詳細的說明:
Driver Vendor DataSource:
Driver Vendor必須提供一個ConnectionPoolDataSource 接口的具體實現(xiàn),通過這個接口Pooling Vendor可以得到一個PooledConnection對象,從而使第三方實現(xiàn)的連接池可以使用特定數(shù)據(jù)庫廠商得到JDBC Driver產(chǎn)生的數(shù)據(jù)庫連接。在這里ConnectionPoolDataSource接口扮演的角色可以視為產(chǎn)生PooledConnection 對象的工廠。
Driver Vendor PooledConnection:
Driver Vendor必須提供標準PooledConnection 接口實現(xiàn)的類,這個接口允許Pooling Vendor在JDBC Driver提供連接池支持的基礎(chǔ)上實現(xiàn)連接池。一個具體PooledConnection對象代表了一個物理的數(shù)據(jù)庫連接;由PooledConnection對象創(chuàng)建Connection對象僅僅只是一個指向PooledConnetion對象的句柄。在JDBC 3.0連接池實現(xiàn)框架中PooledConnection對象扮演的角色可以視為產(chǎn)生Connection對象的工廠。
Pooling Vendor DataSource:
Pooling Vendor必須實現(xiàn)DataSource接口,這個接口是和連接池實現(xiàn)模塊進行交互的入口點。ConnectionPoolDataSource根據(jù)需要創(chuàng)建PooledConnection對象。
Pooling Vendor Connection Cache:
此模塊是Pooling Vendor對連接池的具體實現(xiàn)。JDBC 3.0 規(guī)范沒有規(guī)定在DataSource對象和數(shù)據(jù)庫連接池實現(xiàn)之間的需要實現(xiàn)的接口,所以它們之間的交互由Pooling Vendor自己定義。一般而言,一個數(shù)據(jù)庫連接池的具體實現(xiàn)包含了一個或若干個具體的類,但是在連接池實現(xiàn)模塊中必須包含一個類實現(xiàn)標準ConnectionEventListener接口。當一個PooledConnectiond對象被關(guān)閉或者出現(xiàn)異常的時候,PooledConnection對象將會向ConnectionEventListener接口發(fā)送ConnectionEvent對象,連接池實現(xiàn)模塊將會根據(jù)返回的ConnectionEvent對象對PooledConnection進行關(guān)閉或者重用操作。
ConnectionEvent:
實現(xiàn)連接池時,當應用程序調(diào)用Connection.close()試圖去關(guān)閉數(shù)據(jù)庫連接時,這時需要有一個通告給連接池實現(xiàn)模塊,通告對當前的數(shù)據(jù)庫物理連接(PooledConnection 對象)進行重用。為了使連接池實現(xiàn)模塊能得到這種"通告",連接池實現(xiàn)模塊必須實現(xiàn)ConnectionEventListener接口,而且同時需要注冊成為PooledConnection對象的監(jiān)聽者。連接池實現(xiàn)模塊通過PooledConnection.addConnectionEventListener()方法注冊自己成為一個監(jiān)聽者。
在典型三層環(huán)境中具體調(diào)用流程:
當應用程序通過調(diào)用DataSource.getConnection()得到一個數(shù)據(jù)庫連接。
Pooling Vendor實現(xiàn)的DataSource對象在連接池中進行查找看當前是否有有效的PooledConnection對象,如果連接池中有可用的PooledConnection,則進行檢查,如果當前的PooledConnection可用則使用。
如果如果連接池中沒有可用的PooledConnection對象,或者當前的PooledConnection對象不正確,那么Pooling Vendor調(diào)用ConnectionPoolDataSource.getPooledConnection類創(chuàng)建一個新的PooledConnection對象,這時由Driver Vendor實現(xiàn)的ConnectionPoolDataSource將會創(chuàng)建一個滿足要求新的PooledConnection對象,并將其返回給連接池實現(xiàn)模塊進行管理。
然后,Pooling Vendor會調(diào)用PooledConnection.getConnection()獲得一個邏輯的Connection對象,這個邏輯的Connection對象將會象正常的Connection對象返回給應用程序。這個邏輯Connection對象實際上是連接池中PooledConnection對象的一個句柄,當連接池有效時,應用程序調(diào)用DataSource.getConnection()就會得到這個句柄。簡而言之,應用程序此時使用的Connection對象僅僅是其創(chuàng)建者PooledConnection對象的句柄而已。
連接池實現(xiàn)模塊調(diào)用PooledConnection.addConnectionEventListener()將自己注冊成為一個PooledConnection對象的監(jiān)聽者,當數(shù)據(jù)庫連接需要重用或者關(guān)閉的時候連接池實現(xiàn)模塊可以得到通告。
當應用程序通過調(diào)用Connection.close()來關(guān)閉數(shù)據(jù)庫連接,這時一個ConnectionEvent對象被創(chuàng)建并被返回到連接池實現(xiàn)模塊,連接池實現(xiàn)模塊接受到此通告后,將PooledConnection對象返回到池中進行重用。這些過程中其它角色都不能訪問PooledConnection.close()方法,能訪問這個方法的只有Pooling Vendor,它們使用這個方法對連接池中的對象進行操作,通過PooledConnection.close()方法可以關(guān)閉物理數(shù)據(jù)庫連接。
關(guān)于數(shù)據(jù)庫連接池的基本原理就為大家介紹這么多,希望對大家能夠有所幫助,上文中的內(nèi)容比較適合剛剛?cè)腴T的初學者學習,希望大家不要錯過這篇文章哦。