我刚开始在百度搜索的时,看到一些回答是从Druid的连接池中获取的连接是也由它进行管理,会自动回收。但实践后发现从DruidPooledConnection连接池手动获取的连接是需要关闭的,如果不手动close()关闭会造成连接"泄露",类似内存泄露,也就是不会被回收掉,就占据在哪里,当连接数"达标"——即超过在Druid连接池中配置的最大连接数,即获取不到连接,从而阻塞等待。
1. 从Druid连接池中获取连接
由于业务需要测试SQL语句同时获取结果,而项目整体用的是Druid的连接池,我需要从Druid的连接池中获取一个Connection连接然后进行JDBC的操作。下列是从连接池中获取连接的代码
package com.lwl.monitor.utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.sql.SQLException;
/**
* 单例对象
* 获取DruidDataSource的Connection
* @author lwl
* @create 2021/11/15 21:24
*/
@Component
public class ConnectionUtil {
private ConnectionUtil(){
}
private static ConnectionUtil connectionUtil = null;
@Autowired
private DruidDataSource druidDataSource;
@PostConstruct
public void init(){
connectionUtil = this;
connectionUtil.druidDataSource = this.druidDataSource;
}
/**
* 获取实例
* @return ConnectionUtil
*/
public static ConnectionUtil getInstance(){
if(connectionUtil==null){
synchronized (ConnectionUtil.class){
if(connectionUtil==null){
connectionUtil = new ConnectionUtil();
}
}
}
return connectionUtil;
}
/**
* 获取连接
* @return DruidPooledConnection
*/
public DruidPooledConnection getConnection(){
DruidPooledConnection connection = null;
try {
connection = druidDataSource.getConnection();
//手动控制事务
connection.setAutoCommit(false);
}catch (SQLException e){
e.printStackTrace();
}
return connection;
}
}
2.当业务代码未在finally代码块中关闭连接时的情况
此时未关闭连接,发现前端重复请求时获取到的连接对象均不一致。
当请求次数超过20次,也就是新建了20个连接(我配置的最大连接数为20),之前的连接均未关闭,当新的请求来到时,就会因为获取不到连接而阻塞等待,前端请求也会因为超过默认的等待时间而报timeout超时错误。
而后端由于获取不到连接(这是因为之前的20个手动获取的连接均未手动关闭),超出设置的阻塞等待时间,此时也抛出了异常。
3.当业务代码改为在finally代码块中关闭连接时的情况
当前端重复请求时,可以发现,当我们手动关闭了连接,从DruidPooledConnection连接池中取出的连接都为同一个连接对象。即在连接池中只占据了一个连接数,不会再造成连接“泄露”的问题了。
4.后言
从Druid连接池中手动获取连接后,该连接需要手动关闭,该连接此时并不受Druid的管理关闭,有兴趣的可以去源码探究一波。