在使用開發基於數據庫的web程序時,傳統的模式基本是按如下步驟:java
①在主程序(如servlet、beans)中創建數據庫鏈接。
②進行sql操做
③斷開數據庫鏈接。mysql
這種模式開發,存在的問題:web
①普通的JDBC數據庫鏈接使用 DriverManager 來獲取,每次向數據庫創建連接的時候都要將 Connection 加載到內存中,再驗證用戶名和密碼(得花費0.05s~1s的時間)。須要數據庫鏈接的時候,就向數據庫要求一個,執行完成後再斷開鏈接。這樣的方式將會消耗大量的資源和時間。數據庫的鏈接資源並無獲得很好的重複利用.若同時有幾百人甚至幾千人在線,頻繁的進行數據庫鏈接操做將佔用不少的系統資源,嚴重的甚至會形成服務器的崩潰。
②對於每一次數據庫鏈接,使用完後都得斷開。不然,若是程序出現異常而未能關閉,將會致使數據庫系統中的內存泄漏,最終將致使重啓數據庫。
③這種開發不能控制被建立的鏈接對象數,系統資源會被毫無顧及的分配出去,如鏈接過多,也可能致使內存泄漏,服務器崩潰。sql
爲解決傳統開發中的數據庫鏈接問題,能夠採用數據庫鏈接池技術。數據庫
數據庫鏈接池的基本思想就是爲數據庫鏈接創建一個「緩衝池」。預先在緩衝池中放入必定數量的鏈接,當須要創建數據庫鏈接時,只需從「緩衝池」中取出一個,使用完畢以後再放回去。服務器
數據庫鏈接池負責分配、管理和釋放數據庫鏈接,它容許應用程序重複使用一個現有的數據庫鏈接,而不是從新創建一個。ide
數據庫鏈接池在初始化時將建立必定數量的數據庫鏈接放到鏈接池中,這些數據庫鏈接的數量是由最小數據庫鏈接數來設定的。不管這些數據庫鏈接是否被使用,鏈接池都將一直保證至少擁有這麼多的鏈接數量。鏈接池的最大數據庫鏈接數量限定了這個鏈接池能佔有的最大鏈接數,當應用程序向鏈接池請求的鏈接數超過最大鏈接數量時,這些請求將被加入到等待隊列中。學習
①因爲數據庫鏈接得以重用,避免了頻繁建立,釋放鏈接引發的大量性能開銷。在減小系統消耗的基礎上,另外一方面也增長了系統運行環境的平穩性。大數據
更快的系統反應速度:
數據庫鏈接池在初始化過程當中,每每已經建立了若干數據庫鏈接置於鏈接池中備用。此時鏈接的初始化工做均已完成。對於業務請求處理而言,直接利用現有可用鏈接,避免了數據庫鏈接初始化和釋放過程的時間開銷,從而減小了系統的響應時間ui
新的資源分配手段:
對於多應用共享同一數據庫的系統而言,可在應用層經過數據庫鏈接池的配置,實現某一應用最大可用數據庫鏈接數的限制,避免某一應用獨佔全部的數據庫資源
統一的鏈接管理,避免數據庫鏈接泄露:
在較爲完善的數據庫鏈接池實現中,可根據預先的佔用超時設定,強制回收被佔用鏈接,從而避免了常規數據庫鏈接操做中可能出現的資源泄露
JDBC 的數據庫鏈接池使用 javax.sql.DataSource 來表示,DataSource 只是一個接口,該接口一般由服務器(Weblogic, WebSphere, Tomcat)提供實現,也有一些開源組織提供實現:
①DBCP 數據庫鏈接池
②C3P0 數據庫鏈接池
DataSource 一般被稱爲數據源,它包含鏈接池和連接池管理兩個部分,習慣上也常常把 DataSource稱爲鏈接池
數據源和數據庫鏈接不一樣,數據源無需建立多個,它是產生數據庫鏈接的工廠,所以整個應用只須要一個數據源便可。
當數據庫訪問結束後,程序仍是像之前同樣關閉數據庫鏈接:conn.close(); 但上面的代碼並無關閉數據庫的物理鏈接,它僅僅把數據庫鏈接釋放,歸還給了數據庫鏈接池。
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
通常方式建立數據庫鏈接池:
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】。轉載請註明出處和連接地址,歡迎轉載,謝謝!