如果在JNDI中註冊了數據源對象,將會比起使用DriverManager來具有兩個方面的優勢:
首先,程序不需要像使用DriverManager壹樣對加載的數據庫驅動程序信息進行硬編碼,程序員可以選擇先在JNDI中註冊這個數據源對象,然後在 程序中使用壹個邏輯名稱來引用它,JNDI會自動根據妳給出的名稱找到與這個名稱綁定的DataSource對象。然後就可以使用這個 DataSource對象來建立和具體數據庫的連接了。
其次,使用實現了DataSource接口的類所具有的第二個優勢體現在連接池和分布式事務上。連接池通過對連接的復用而不是新建壹個物理連接來顯著地提高程序的效率。從而適用於任務繁忙、負擔繁重的企業級分布式事務。
數據庫連接池的基本原理
傳統的數據庫連接方式(指通過DriverManager和基本實現DataSource進行連接)中,壹個數據庫連接對象均對應壹個物理數據庫連接,數 據庫連接的建立以及關閉對系統而言是耗費系統資源的操作,在多層結構的應用程序環境中這種耗費資源的動作對系統的性能影響尤為明顯。
在多層結構的應用程序中通過連接池(connection pooling)技術可以使系統的性能明顯得到提到,連接池意味著當應用程序需要調用壹個數據庫連接的時,數據庫相關的接口通過返回壹個通過重用數據庫連 接來代替重新創建壹個數據庫連接。通過這種方式,應用程序可以減少對數據庫連接操作,尤其在多層環境中多個客戶端可以通過***享少量的物理數據庫連接來滿足 系統需求。通過連接池技術Java應用程序不僅可以提高系統性能同時也為系統提高了可測量性。
數據庫連接池是運行在後臺的而且應用程序的編碼沒有任何的影響。此中狀況存在的前提是應用程序必須通過DataSource對象(壹個實現 javax.sql.DataSource接口的實例)的方式代替原有通過DriverManager類來獲得數據庫連接的方式。壹個實現 javax.sql.DataSource接口的類可以支持也可以不支持數據庫連接池,但是兩者獲得數據庫連接的代碼基本是相同的。
壹個DataSource對象通常註冊在JNDI命名服務上,應用程序可以通過標準的方式獲得到註冊在JNDI服務上的DataSource對象。 代碼如下:
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("jdbc/openbase");
如果當前DataSource不支持數據庫連接池,應用程序將獲得壹個和物理數據庫連接對應的Connection對象。而如果當前的 DataSource對象支持數據庫連接池,應用程序自動獲得重用的數據庫連接而不用創建新的數據庫連接。重用的數據庫連接和新建立連接的數據庫連接使用 上沒有任何不同。應用程序可以通過重用的連接正常的訪問數據庫,進行訪問數據的操作,完成操作後應顯式的調用close()關閉數據庫連接。
Connection con = ds.getConnection("User", "Pwd");
相關數據庫的操作;
con.close();
當關閉數據連接後,當前使用的數據庫連接將不會被物理關閉,而是放回到數據庫連接池中進行重用。
JDBC3.0規範中數據庫連接池框架
JDBC3.0規範中通過提供了壹個支持數據庫連接池的框架,這個框架僅僅規定了如何支持連接池的實現,而連接池的具體實現JDBC 3.0規範並沒有做相關的規定。通過這個框架可以讓不同角色的開發人員***同實現數據庫連接池。
通過JDBC3.0規範可以知道具體數據庫連接池的實現可以分為JDBC Driver級和Application Server級。在JDBC Driver級的實現中任何相關的工作均由特定數據庫廠商的JDBC Drvier的開發人員來具體實現,即JDBC Driver既需要提供對數據庫連接池的支持同時也必須對數據庫連接池進行具體實現。而在Application Server級中數據庫連接池的實現中特定數據庫廠商的JDBC Driver開發人員和Application Server開發人員來***同實現數據庫連接池的實現(但是現在大多數Application Server廠商實現的連接池的機制和規範中提到有差異),其中特定數據庫廠商的JDBC Driver提供數據庫連接池的支持而特定的Application Server廠商提供數據庫連接池的具體實現。
JDBC3.0規範規定了如下的類和接口來支持數據庫連接池的實現。
javax.sql.ConnectionEvent
javax.sql.ConnectionPoolDataSource
javax.sql.PooledConnection
javax.sql.ConnectionEventListener
其中除javax.sql.ConnectionEvent是類,其它的均為接口。
C:/1.jpg
screen.width-333)this.width=screen.width-333;" src="/Develop/ArticleImages/19/19446/CSDN_Dev_Image_2003-7-41948411.jpg">
JDBC3.0連接池框架的關系圖
通過此圖可以大概的了解相關接口在壹個典型的三層環境中應用程序的位置。
數據庫連接池實現層次中,由特定數據庫廠商的JDBC Driver開發人員提供連接池支持,而特定Application Server提供連接池實現的情況比較復雜,其它的實現層次均可視為其簡化情況的壹種。下面將針對這種情況進行說明。
在這個框架主要有兩個用戶角色存在,它們分別是:
特定數據庫廠商的JDBC Driver開發人員,之後將簡稱為Driver Vendor
特定Application Server中連接池開發人員,之後將簡稱為Pooling Vendor
C:/2.bmp
screen.width-333)this.width=screen.width-333;" src="/Develop/ArticleImages/19/19446/CSDN_Dev_Image_2003-7-41948413.gif">
JDBC3.0規範中在上述情況下各個接口和類之間的UML圖
下面對幾個關鍵模塊進行詳細的說明:
Driver Vendor DataSource:
Driver Vendor必須提供壹個ConnectionPoolDataSource 接口的具體實現,通過這個接口Pooling Vendor可以得到壹個PooledConnection對象,從而使第三方實現的連接池可以使用特定數據庫廠商得到JDBC Driver產生的數據庫連接。在這裏ConnectionPoolDataSource接口扮演的角色可以視為產生PooledConnection 對象的工廠。
Driver Vendor PooledConnection:
Driver Vendor必須提供標準PooledConnection 接口實現的類,這個接口允許Pooling Vendor在JDBC Driver提供連接池支持的基礎上實現連接池。壹個具體PooledConnection對象代表了壹個物理的數據庫連接;由 PooledConnection對象創建Connection對象僅僅只是壹個指向PooledConnetion對象的句柄。在JDBC 3.0連接池實現框架中PooledConnection對象扮演的角色可以視為產生Connection對象的工廠。
Pooling Vendor DataSource:
Pooling Vendor必須實現DataSource接口,這個接口是和連接池實現模塊進行交互的入口點。ConnectionPoolDataSource根據需要創建PooledConnection對象。
Pooling Vendor Connection Cache:
此模塊是Pooling Vendor對連接池的具體實現。JDBC 3.0 規範沒有規定在DataSource對象和數據庫連接池實現之間的需要實現的接口,所以它們之間的交互由Pooling Vendor自己定義。壹般而言,壹個數據庫連接池的具體實現包含了壹個或若幹個具體的類,但是在連接池實現模塊中必須包含壹個類實現標準 ConnectionEventListener接口。當壹個PooledConnectiond對象被關閉或者出現異常的時 候,PooledConnection對象將會向ConnectionEventListener接口發送ConnectionEvent對象,連接池實 現模塊將會根據返回的ConnectionEvent對象對PooledConnection進行關閉或者重用操作。
ConnectionEvent:
實現連接池時,當應用程序調用Connection.close()試圖去關閉數據庫連接時,這時需要有壹個通告給連接池實現模塊,通告對當前的數據 庫物理連接(PooledConnection 對象)進行重用。為了使連接池實現模塊能得到這種"通告",連接池實現模塊必須實現ConnectionEventListener接口,而且同時需要註 冊成為PooledConnection對象的監聽者。連接池實現模塊通過 PooledConnection.addConnectionEventListener()方法註冊自己成為壹個監聽者。
在典型三層環境中具體調用流程:
當應用程序通過調用DataSource.getConnection()得到壹個數據庫連接。
Pooling Vendor實現的DataSource對象在連接池中進行查找看當前是否有有效的PooledConnection對象,如果連接池中有可用的PooledConnection,則進行檢查,如果當前的PooledConnection可用則使用。
如果如果連接池中沒有可用的PooledConnection對象,或者當前的PooledConnection對象不正確,那麽Pooling Vendor調用ConnectionPoolDataSource.getPooledConnection類創建壹個新的 PooledConnection對象,這時由Driver Vendor實現的ConnectionPoolDataSource將會創建壹個滿足要求新的PooledConnection對象,並將其返回給連接 池實現模塊進行管理。
然後,Pooling Vendor會調用PooledConnection.getConnection()獲得壹個邏輯的Connection對象,這個邏輯的 Connection對象將會象正常的Connection對象返回給應用程序。這個邏輯Connection對象實際上是連接池中 PooledConnection對象的壹個句柄,當連接池有效時,應用程序調用DataSource.getConnection()就會得到這個句 柄。簡而言之,應用程序此時使用的Connection對象僅僅是其創建者PooledConnection對象的句柄而已。
連接池實現模塊調用PooledConnection.addConnectionEventListener()將自己註冊成為壹個PooledConnection對象的監聽者,當數據庫連接需要重用或者關閉的時候連接池實現模塊可以得到通告。
當應用程序通過調用Connection.close()來關閉數據庫連接,這時壹個ConnectionEvent對象被創建並被返回到連接池實現 模塊,連接池實現模塊接受到此通告後,將PooledConnection對象返回到池中進行重用。這些過程中其它角色都不能訪問 PooledConnection.close()方法,能訪問這個方法的只有Pooling Vendor,它們使用這個方法對連接池中的對象進行操作,通過PooledConnection.close()方法可以關閉物理數據庫連接。