JDBC數據庫連接池
一、JDBC數據庫連接池的必要性
在使用開發基於數據庫的web程序時,傳統的模式基本是按以下步驟:
①在主程序(如servlet、beans)中建立數據庫連接。
②進行sql操作
③斷開數據庫連接。
這種模式開發,存在的問題:
①普通的JDBC數據庫連接使用 DriverManager 來獲取,每次向數據庫建立連接的時候都要將 Connection 加載到內存中,再驗證用戶名和密碼(得花費0.05s~1s的時間)。需要數據庫連接的時候,就向數據庫要求一個,執行完成后再斷開連接。這樣的方式將會消耗大量的資源和時間。數據庫的連接資源並沒有得到很好的重復利用.若同時有幾百人甚至幾千人在線,頻繁的進行數據庫連接操作將占用很多的系統資源,嚴重的甚至會造成服務器的崩潰。
②對於每一次數據庫連接,使用完后都得斷開。否則,如果程序出現異常而未能關閉,將會導致數據庫系統中的內存泄漏,最終將導致重啟數據庫。
③這種開發不能控制被創建的連接對象數,系統資源會被毫無顧及的分配出去,如連接過多,也可能導致內存泄漏,服務器崩潰。
二、數據庫連接池(connection pool)
數據庫連接池簡單介紹
為解決傳統開發中的數據庫連接問題,可以采用數據庫連接池技術。
數據庫連接池的基本思想就是為數據庫連接建立一個“緩沖池”。預先在緩沖池中放入一定數量的連接,當需要建立數據庫連接時,只需從“緩沖池”中取出一個,使用完畢之后再放回去。
數據庫連接池負責分配、管理和釋放數據庫連接,它允許應用程序重復使用一個現有的數據庫連接,而不是重新建立一個。
數據庫連接池在初始化時將創建一定數量的數據庫連接放到連接池中,這些數據庫連接的數量是由最小數據庫連接數來設定的。無論這些數據庫連接是否被使用,連接池都將一直保證至少擁有這么多的連接數量。連接池的最大數據庫連接數量限定了這個連接池能占有的最大連接數,當應用程序向連接池請求的連接數超過最大連接數量時,這些請求將被加入到等待隊列中。
數據庫連接池工作原理:
數據庫連接池技術的優點
資源重用:
①由於數據庫連接得以重用,避免了頻繁創建,釋放連接引起的大量性能開銷。在減少系統消耗的基礎上,另一方面也增加了系統運行環境的平穩性。
更快的系統反應速度:
數據庫連接池在初始化過程中,往往已經創建了若干數據庫連接置於連接池中備用。此時連接的初始化工作均已完成。對於業務請求處理而言,直接利用現有可用連接,避免了數據庫連接初始化和釋放過程的時間開銷,從而減少了系統的響應時間
新的資源分配手段:
對於多應用共享同一數據庫的系統而言,可在應用層通過數據庫連接池的配置,實現某一應用最大可用數據庫連接數的限制,避免某一應用獨占所有的數據庫資源
統一的連接管理,避免數據庫連接泄露:
在較為完善的數據庫連接池實現中,可根據預先的占用超時設定,強制回收被占用連接,從而避免了常規數據庫連接操作中可能出現的資源泄露
三、兩種開源的數據庫連接池
JDBC 的數據庫連接池使用 javax.sql.DataSource 來表示,DataSource 只是一個接口,該接口通常由服務器(Weblogic, WebSphere, Tomcat)提供實現,也有一些開源組織提供實現:
①DBCP 數據庫連接池
②C3P0 數據庫連接池
DataSource 通常被稱為數據源,它包含連接池和連接池管理兩個部分,習慣上也經常把 DataSource稱為連接池
數據源和數據庫連接不同,數據源無需創建多個,它是產生數據庫連接的工廠,因此整個應用只需要一個數據源即可。
當數據庫訪問結束后,程序還是像以前一樣關閉數據庫連接:conn.close(); 但上面的代碼並沒有關閉數據庫的物理連接,它僅僅把數據庫連接釋放,歸還給了數據庫連接池。
DBCP 數據源
DBCP 是 Apache 軟件基金組織下的開源連接池實現,該連接池依賴該組織下的另一個開源系統:Common-pool.如需使用該連接池實現,應在系統中增加如下兩個 jar文件:
①Commons-dbcp.jar:連接池的實現
②Commons-pool.jar:連接池實現的依賴庫
Tomcat 的連接池正是采用該連接池來實現的。該數據庫連接池既可以與應用服務器整合使用,也可由應用程序獨立使用。
使用范例:

1 /**
2 * 使用 DBCP 數據庫連接池 3 * 1. 加入 jar 包(2 個jar 包). 依賴於 Commons Pool 4 * 2. 創建數據庫連接池 5 * 3. 為數據源實例指定必須的屬性 6 * 4. 從數據源中獲取數據庫連接 7 * 8 * @throws SQLException 9 */
10 @Test 11 public void testDBCP() throws SQLException { 12 final BasicDataSource dataSource = new BasicDataSource(); 13
14 // 2. 為數據源實例指定必須的屬性
15 dataSource.setUsername("root"); 16 dataSource.setPassword(""); 17 dataSource.setUrl("jdbc:mysql:///jdbc?useSSL=false"); 18 dataSource.setDriverClassName("com.mysql.jdbc.Driver"); 19
20 // 3. 指定數據源的一些可選的屬性. 21 // 1). 指定數據庫連接池中初始化連接數的個數
22 dataSource.setInitialSize(5); 23
24 // 2). 指定最大的連接數: 同一時刻可以同時向數據庫申請的連接數
25 dataSource.setMaxActive(5); 26
27 // 3). 指定小連接數: 在數據庫連接池中保存的最少的空閑連接的數量
28 dataSource.setMinIdle(2); 29
30 // 4).等待數據庫連接池分配連接的最長時間. 單位為毫秒. 超出該時間將拋出異常.
31 dataSource.setMaxWait(1000 * 5); 32
33 // 4. 從數據源中獲取數據庫連接
34 Connection connection = dataSource.getConnection(); 35 System.out.println(connection.getClass()); 36
37 connection = dataSource.getConnection(); 38 System.out.println(connection.getClass()); 39
40 connection = dataSource.getConnection(); 41 System.out.println(connection.getClass()); 42
43 connection = dataSource.getConnection(); 44 System.out.println(connection.getClass()); 45
46 Connection connection2 = dataSource.getConnection(); 47 System.out.println(">" + connection2.getClass()); 48
49 new Thread() { 50 public void run() { 51 Connection conn; 52 try { 53 conn = dataSource.getConnection(); 54 System.out.println(conn.getClass()); 55 } catch (SQLException e) { 56 e.printStackTrace(); 57 } 58 }; 59 }.start(); 60
61 try { 62 Thread.sleep(3000); 63 } catch (InterruptedException e) { 64 e.printStackTrace(); 65 } 66
67 connection2.close(); 68 }
使用配置文件的方式:

1 /**
2 * 1. 加載 dbcp 的 properties 配置文件: 配置文件中的鍵需要來自 BasicDataSource 的屬性. 3 * 2. 調用BasicDataSourceFactory 的 createDataSource 方法創建 DataSource 實例 4 * 3. 從DataSource 實例中獲取數據庫連接. 5 */
6 @Test 7 public void testDBCPWithDataSourceFactory() throws Exception { 8
9 Properties properties = new Properties(); 10 InputStream inStream = JDBCTest.class.getClassLoader().getResourceAsStream("dbcp.properties"); 11 properties.load(inStream); 12
13 DataSource dataSource = BasicDataSourceFactory.createDataSource(properties); 14
15 System.out.println(dataSource.getConnection()); 16
17 // BasicDataSource basicDataSource = 18 // (BasicDataSource) dataSource; 19 //
20 // System.out.println(basicDataSource.getMaxWait());
21 }
注意:這里使用配置文件的方式應遵循Java EE的setter和getter規范,不能隨便命名:
dbcp.properties配置文件(屬性的意義和第一種方式對應):
username=root
password=password
driverClassName=com.mysql.jdbc.Driver
#這里MySQL高版本驅動需要設置useSSL=false或true,否則控制台會有警告
url=jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=UTF-8&useSSL=false
initialSize=10
maxActive=50
minIdle=5
maxWait=5000
C3P0數據源
一般方式創建數據庫連接池:
1 /**
2 * 使用set方法為屬性賦值 3 */
4 @Test 5 public void testC3P0() throws Exception { 6 ComboPooledDataSource cpds = new ComboPooledDataSource(); 7 cpds.setDriverClass("com.mysql.jdbc.Driver"); // loads the jdbc driver
8 cpds.setJdbcUrl("jdbc:mysql:///jdbc?useSSL=false"); 9 cpds.setUser("root"); 10 cpds.setPassword(""); 11
12 System.out.println(cpds.getConnection()); 13 }
使用xml配置文件:
①Java代碼:

1 /**
2 * 1. 創建 c3p0-config.xml 文件, 參考幫助文檔中 Appendix B: Configuation Files 的內容 3 * 2. 創建 ComboPooledDataSource 實例; 4 * DataSource dataSource = new ComboPooledDataSource("helloc3p0"); 5 * 3. 從 DataSource 實例中獲取數據庫連接. 6 */
7 @Test 8 public void testC3poWithConfigFile() throws Exception { 9 DataSource dataSource = new ComboPooledDataSource("helloc3p0"); 10
11 System.out.println(dataSource.getConnection()); 12
13 ComboPooledDataSource comboPooledDataSource = (ComboPooledDataSource) dataSource; 14 System.out.println(comboPooledDataSource.getMaxStatements()); 15 }
②C3P0-config.xml配置文件:

1 <?xml version="1.0" encoding="UTF-8"?>
2 <c3p0-config>
3
4 <named-config name="helloc3p0">
5
6 <!-- 指定連接數據源的基本屬性 -->
7 <property name="user">root</property>
8 <property name="password"></property>
9 <property name="driverClass">com.mysql.jdbc.Driver</property>
10 <property name="jdbcUrl">jdbc:mysql:///jdbc?useSSL=false</property>
11
12 <!-- 若數據庫中連接數不足時, 一次向數據庫服務器申請多少個連接 -->
13 <property name="acquireIncrement">5</property>
14 <!-- 初始化數據庫連接池時連接的數量 -->
15 <property name="initialPoolSize">5</property>
16 <!-- 數據庫連接池中的最小的數據庫連接數 -->
17 <property name="minPoolSize">5</property>
18 <!-- 數據庫連接池中的最大的數據庫連接數 -->
19 <property name="maxPoolSize">10</property>
20
21 <!-- C3P0 數據庫連接池可以維護的 Statement 的個數 -->
22 <property name="maxStatements">20</property>
23 <!-- 每個連接同時可以使用的 Statement 對象的個數 -->
24 <property name="maxStatementsPerConnection">5</property>
25
26 </named-config>
27
28 </c3p0-config>
如果,您對我的這篇博文有什么疑問,歡迎評論區留言,大家互相討論學習。
如果,您認為閱讀這篇博客讓您有些收獲,不妨點擊一下右下角的【推薦】。
如果,您希望更容易地發現我的新博客,不妨點擊一下左下角的【關注我】。
如果,您對我的博文感興趣,可以關注我的后續博客,我是【AlbertRui】。轉載請注明出處和鏈接地址,歡迎轉載,謝謝!