你不得不知道的数据库连接池的信息
数据库连接池是用来保持与数据库的连接,从而便于复用。
首先我们需要知道程序与数据库是一个非常耗费资源的事情,尤其是程序与数据库不在同一台机器上时,必须要开启网络的连接,以及双方的互相验证等等。如果没有连接池的话,那么每次查询都要进行连接、验证、关闭等操作,会非常的耗时耗力,连接池能够保持连接,从而避免了多次建立连接的损耗。
上图就是一个简单的连接池的图示信息,每次程序取得连接时其实是从连接池中取得连接,然后每次关闭的时候将此连接放入连接池中,然后连接池会自己根据一些规则定义连接在池子中保持多少、保持多久。
所以从上面描述我们可以知道在连接池中重要的就是③⑥两个步骤了,什么时候真正建立连接和什么时候真正的关闭连接。
其实我们也能够自己实现一个非常简单的连接池。简单的只需要几步即可
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;
//1、加载Mysql连接
try {
Class.forName("com.mysql.jdbc.Driver");
//2、通过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);
}
}
复制代码
当然了这只是非常简单的一个连接池实现,完整的连接池要考虑的非常多。例如常用的连接池配置中的几个参数,最大连接数量、空闲连接的数量、使用连接前验证连接是否可用等等。
接下来我们用一个常见的异常来回顾一下常见的数据库连接池的一些配置信息。
错误回顾
之前在开发过程中碰到一个异常,随机出现的,异常信息如下
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"/>
复制代码
经过网上查询知道出现这个错误的原因是:程序要使用数据库连接时会从线程池中拿出线程,但是此时连接池中从空闲连接中取出的线程在数据库端被断开了,在程序端并不知道此连接被断开,所以会爆此错误。当然被断开的原因有许多,例如数据库端防火墙控制会清除连接了多久的空闲连接。
所以只需要在配置文件中加入validationQuery="select 1 from dual"
这个参数即可,这个参数是在每次使用时都会验证是否是有效连接。
或者也可以加上minEvictableIdleTimeMillis="3000000"
此参数,表示空闲多久的连接会被在连接池中丢弃掉。此参数常常小于数据库端防火墙配置的清除空闲连接的时间。
如果在DBCP中配置了minEvictableIdleTimeMillis参数,也要配置testWhileIdle="true"参数,此参数是开启异步Evict的TimerTask定时线程进行控制。
常用的参数如下
参数 | 作用 |
---|---|
initialSize | 初始化连接池中连接数量 |
removeAbandoned | 是否自动回收超时连接 |
removeAbandonedTimeout | 超时时间 |
maxActive | 最大连接数量 |
minIdle | 最小空闲连接 |
maxIdle | 最大空闲连接 |
常用的这些,另外全部的话可以看DBCP官方文档说明。
其实所有的连接池的配置信息都差不多就这些参数,参数名称不一样而已。