數(shù)據(jù)庫鏈接的建立和關(guān)閉是極其耗費(fèi)系統(tǒng)資源的操作村生。通過DriverManager獲取的數(shù)據(jù)庫連接懦冰,一個數(shù)據(jù)庫連接對象均對應(yīng)一個物理數(shù)據(jù)庫連接黄绩,每次操作都打開一個物理連接,使用完后立即關(guān)閉連接其垄。頻繁的打開苛蒲、關(guān)閉連接將造成系統(tǒng)性能的低下。
對于共享資源的情況绿满,有一個通用版的設(shè)計模式:資源池臂外。用于解決資源的頻繁請求、釋放所造成的性能下降。為了解決數(shù)據(jù)庫連接的頻繁請求漏健、釋放嚎货,JDBC2.0引入了數(shù)據(jù)庫連接池技術(shù)。
數(shù)據(jù)庫連接池蔫浆,在系統(tǒng)啟動時殖属,就主動建立足夠的數(shù)據(jù)庫連接,并將這些連接組成一個連接池瓦盛。每次應(yīng)用程序請求數(shù)據(jù)庫連接時洗显,無須重新打開連接,而是從連接池中取出已有的鏈接使用原环,使用完畢后不再關(guān)閉數(shù)據(jù)庫連接挠唆,而是直接將連接歸還給連接池。
數(shù)據(jù)庫連接池是Connection對象的工廠扮念。數(shù)據(jù)庫連接池的常用參數(shù)如下:
- 數(shù)據(jù)庫的初始連接池
- 連接池的最大連接數(shù)
- 連接池的最小連接池
- 連接池每次增加的容量
JDBC的數(shù)據(jù)庫連接池使用javax.sql.DataSource來表示,DataSource只是一個接口碧库,該接口通常由商用服務(wù)器等提供實現(xiàn)柜与,也有一些開源組織提供實現(xiàn)(DBCP、C3P0)嵌灰。
DataSource通常被稱為數(shù)據(jù)源弄匕,它包含連接池和連接池管理兩個部分,但習(xí)慣上也經(jīng)常把DataSource稱為連接池沽瞭。
DataSource有三種類型的實現(xiàn):
- 基本實現(xiàn)——生成標(biāo)準(zhǔn)Connection對象
- 連接池實現(xiàn)——生成自動參與連接池的Connection 對象迁匠。此實現(xiàn)與中間層連接池管理器一起使用。
- 分布式事務(wù)實現(xiàn)——生成一個Connection 對象驹溃,該對象可用于分布式事務(wù)城丧,并且?guī)缀跏冀K參與連接池。此實現(xiàn)與中間層事務(wù)管理器一起使用豌鹤,并且?guī)缀跏冀K與連接池管理器一起使用亡哄。DataSource對象的屬性在需要時可以修改。例如布疙,如果將數(shù)據(jù)源移動到另一個服務(wù)器蚊惯,則可更改與服務(wù)器相關(guān)的屬性。其優(yōu)點(diǎn)是灵临,因為可以更改數(shù)據(jù)源的屬性截型,所以任何訪問該數(shù)據(jù)源的代碼都無需更改。
在Spring與Hibernate儒溉、Mybatis等ORM框架的整合過程中宦焦,DataSource扮演著非常重要的角色。
DBCP數(shù)據(jù)源
開源系統(tǒng):common-pool。如果需要使用該連接池實現(xiàn)赶诊,則應(yīng)在系統(tǒng)中增加如下兩個jar文件笼平。
- commons-dbcp.jar:連接池的實現(xiàn)
- commons-pool.jar:連接池實現(xiàn)的依賴庫
Tomcat的連接池正是采用該連接池實現(xiàn)的。數(shù)據(jù)庫連接池既可以與應(yīng)用服務(wù)器整合使用舔痪,也可以由應(yīng)用程序獨(dú)立使用寓调。
//創(chuàng)建數(shù)據(jù)源對象
BasicDataSource ds = new BasicDataSource();
//設(shè)置連接池所需的驅(qū)動
ds.setDriverClassName("com.mysql.jdbc.Driver");
//設(shè)置鏈接數(shù)據(jù)庫的URL
ds.setUrl("jdbc:mysql://localhost:3306/javaee");
//設(shè)置連接數(shù)據(jù)庫的用戶名
ds.setUsername("root");
//設(shè)置連接數(shù)據(jù)庫的密碼
ds.setPassword("pass");
//設(shè)置連接池的初始連接數(shù)
ds.setInitialSize(5);
//設(shè)置連接池最多可有多少個活動連接數(shù)
ds.setMaxActive(20);
//設(shè)置連接池中最少有兩個空閑的鏈接
ds.setMinTdle(2);
數(shù)據(jù)源和數(shù)據(jù)庫連接不同,數(shù)據(jù)源無須創(chuàng)建多個锄码,它是產(chǎn)生數(shù)據(jù)庫連接的工廠夺英,因此整個應(yīng)用只需要一個數(shù)據(jù)源即可。建議把上面的ds設(shè)置成static成員變量滋捶,并且在應(yīng)用開始時立即初始化數(shù)據(jù)源對象痛悯,程序中所有需要獲取數(shù)據(jù)庫連接的地方直接訪問該ds對象。并獲取數(shù)據(jù)庫連接即可重窟。
// 通過數(shù)據(jù)源獲取數(shù)據(jù)庫連接
Connection conn = ds.getConnection();
當(dāng)數(shù)據(jù)庫訪問結(jié)束后载萌,關(guān)閉數(shù)據(jù)庫連接。
// 釋放數(shù)據(jù)庫連接
conn.close();
C3P0數(shù)據(jù)源
相比之下巡扇,c3p0 的數(shù)據(jù)源性能更勝一籌扭仁,Hibernate推薦使用該連接池。C3P0連接池不僅可以自動清理不使用的Connection厅翔,還可以自動清理Statement和ResultSet乖坠。
c3p0-0.9.1.2.jar
//創(chuàng)建連接池實例
ComboPooledDataSource ds = new ComboPooledDataSource();
//設(shè)置連接池連接數(shù)據(jù)庫所需的驅(qū)動
ds.setDriverClass("com.mysql.jdbc.Driver");
//設(shè)置鏈接數(shù)據(jù)庫的URL
ds.setJdbcUrl("jdbc:mysql://localhost:3306/javaee");
//設(shè)置連接數(shù)據(jù)庫的用戶名
ds.setUser("root");
//設(shè)置連接數(shù)據(jù)庫的密碼
ds.setPassword("pass");
//設(shè)置連接池的最大連接數(shù)
ds.setMaxPoolSize(40);
//設(shè)置連接池的最小連接數(shù)
ds.setMinPoolSize(2);
//設(shè)置連接池的初始連接數(shù)
ds.setInitialPoolSize(5);
//設(shè)置連接池的緩存Statement的最大數(shù)
ds.setMaxStatements(180);
一旦獲取了C3P0連接池之后,獲取數(shù)據(jù)庫連接:
Connection conn = ds.getConnection();