數據庫鏈接池是用來保持與數據庫的鏈接,從而便於複用。html
首先咱們須要知道程序與數據庫是一個很是耗費資源的事情,尤爲是程序與數據庫不在同一臺機器上時,必需要開啓網絡的鏈接,以及雙方的互相驗證等等。若是沒有鏈接池的話,那麼每次查詢都要進行鏈接、驗證、關閉等操做,會很是的耗時耗力,鏈接池可以保持鏈接,從而避免了屢次創建鏈接的損耗。java
上圖就是一個簡單的鏈接池的圖示信息,每次程序取得鏈接時實際上是從鏈接池中取得鏈接,而後每次關閉的時候將此鏈接放入鏈接池中,而後鏈接池會本身根據一些規則定義鏈接在池子中保持多少、保持多久。mysql
因此從上面描述咱們能夠知道在鏈接池中重要的就是③⑥兩個步驟了,何時真正創建鏈接和何時真正的關閉鏈接。spring
其實咱們也可以本身實現一個很是簡單的鏈接池。簡單的只須要幾步便可sql
public class MyDataSource implements DataSource {
private LinkedList<Connection> dataSources = new LinkedList<>();
public MyDataSource(){
//一次性建立10個鏈接
for(int i = 0; i < 10; i++) {
try {
createConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public Connection createConnection(){
Connection con = null;
//一、加載Mysql鏈接
try {
Class.forName("com.mysql.jdbc.Driver");
//二、經過JDBC創建數據庫鏈接
con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/sys", "帳號", "密碼");
} catch (Exception e) {
e.printStackTrace();
}
return con;
}
@Override
public Connection getConnection(){
if (dataSources.size()>0){
return dataSources.removeFirst();
}else {
return createConnection();
}
}
public void releaseConnection(Connection connection){
dataSources.add(connection);
}
}
複製代碼
固然了這只是很是簡單的一個鏈接池實現,完整的鏈接池要考慮的很是多。例如經常使用的鏈接池配置中的幾個參數,最大鏈接數量、空閒鏈接的數量、使用鏈接前驗證鏈接是否可用等等。數據庫
接下來咱們用一個常見的異常來回顧一下常見的數據庫鏈接池的一些配置信息。apache
以前在開發過程當中碰到一個異常,隨機出現的,異常信息以下bash
org.springframework.jdbc.support.MetaDataAccessException: Error while extracting DatabaseMetaData; nested exception is java.sql.SQLRecoverableException: Closed Connection
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:296)
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:320)
at org.springframework.jdbc.support.SQLErrorCodesFactory.getErrorCodes(SQLErrorCodesFactory.java:214)
複製代碼
咱們的項目使用的鏈接時DBCP,配置以下網絡
<Resource auth="Container" driverClassName="oracle.jdbc.OracleDriver" factory="org.apache.commons.dbcp.BasicDataSourceFactory" maxActive="100" maxIdle="30" maxWait="5000" name="jdbc/riskDs" password="password" type="javax.sql.DataSource" url="jdbc:oracle:thin:@ip:xxx:xxx" username="username"/>
複製代碼
通過網上查詢知道出現這個錯誤的緣由是:程序要使用數據庫鏈接時會從線程池中拿出線程,可是此時鏈接池中從空閒鏈接中取出的線程在數據庫端被斷開了,在程序端並不知道此鏈接被斷開,因此會爆此錯誤。固然被斷開的緣由有許多,例如數據庫端防火牆控制會清除鏈接了多久的空閒鏈接。oracle
因此只須要在配置文件中加入validationQuery="select 1 from dual"
這個參數便可,這個參數是在每次使用時都會驗證是不是有效鏈接。
或者也能夠加上minEvictableIdleTimeMillis="3000000"
此參數,表示空閒多久的鏈接會被在鏈接池中丟棄掉。此參數經常小於數據庫端防火牆配置的清除空閒鏈接的時間。
若是在DBCP中配置了minEvictableIdleTimeMillis參數,也要配置testWhileIdle="true"參數,此參數是開啓異步Evict的TimerTask定時線程進行控制。
經常使用的參數以下
參數 | 做用 |
---|---|
initialSize | 初始化鏈接池中鏈接數量 |
removeAbandoned | 是否自動回收超時鏈接 |
removeAbandonedTimeout | 超時時間 |
maxActive | 最大鏈接數量 |
minIdle | 最小空閒鏈接 |
maxIdle | 最大空閒鏈接 |
經常使用的這些,另外所有的話能夠看DBCP官方文檔說明。
其實全部的鏈接池的配置信息都差很少就這些參數,參數名稱不同而已。