当前位置:网站首页>数据源连接池未关闭的问题 Could not open JDBC Connection for transaction
数据源连接池未关闭的问题 Could not open JDBC Connection for transaction
2022-06-29 08:55:00 【milugloomy】
背景
公司线上运行的项目最近报了这个错,Could not open JDBC Connection for transaction,无法获取数据源连接池了。
分析
阅读源码,看看各个情况下是否都能自动释放数据源连接吧。
MyBatis释放连接
MyBatis自己单独运行的时候运行SQL语句是不会自动释放数据源连接的,但和Spring整合后就会自动释放数据源连接了。Spring改变了MyBatis的SqlSession,改成Spring整合包中的SqlSessionTemplate,关键代码如下:
public class SqlSessionTemplate implements SqlSession, DisposableBean {
//...
//省略一些代码
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}
}
在最后的finally中,会关闭session,释放数据源连接。
事务@Transactional释放连接
在方法上添加注解@Transactional将该方法标记成事务,也会自动释放连接,关键代码如下:
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
//...
//省略一些代码
@Override
protected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.unbindResource(this.dataSource);
}
Connection con = txObject.getConnectionHolder().getConnection();
try {
if (txObject.isMustRestoreAutoCommit()) {
con.setAutoCommit(true);
}
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
}
catch (Throwable ex) {
logger.debug("Could not reset JDBC Connection after transaction", ex);
}
if (txObject.isNewConnectionHolder()) {
if (logger.isDebugEnabled()) {
logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
}
DataSourceUtils.releaseConnection(con, this.dataSource);
}
txObject.getConnectionHolder().clear();
}
这其中,DataSourceUtils.releaseConnection(con, this.dataSource)方法会关闭数据源连接。
找问题
公司项目用的是Druid数据源,最大连接数设的50,按照上面的分析,一般情况下是不可能用完的,肯定是有代码没有释放连接。
找了好半天,最终定位到如下代码:
@Autowired
private SqlSessionFactory sqlSessionFactory;
public void batchInsert(List<TaskCenter> list) {
if(list == null || list.size() == 0){
return;
}
try {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TaskCenterMapper mapper = sqlSession.getMapper(TaskCenterMapper.class);
for(TaskCenter taskCenter : list){
mapper.insertSelective(taskCenter);
}
sqlSession.flushStatements();
sqlSession.commit();
log.info("批量插入成功: " + list.size()+"条数据");
}catch (Exception ex){
log.error("批量插入失败: ", ex);
}
}
这段代码的意思是使用MyBatis的批量插入功能批量插入数据,我们上面分析过,使用MyBatis的SqlSession是不会自动关闭数据源连接的,需要使用Spring包装过的SqlSessionTemplate才会自动关闭数据源连接。所以每次执行这个batchInsert方法,都会占用一个数据源连接而不会释放,最终导致数据源连接池被占满,无法开启新的连接。
解决问题
根据以上的分析,现在有两种方案可以解决该问题
1、将该方法加入事务,在方法上增加注解@Transactional,代码如下:
@Transactional
public void batchInsert(List<TaskCenter> list) {
if(list == null || list.size() == 0){
return;
}
// 以下省略
// ...
2、使用完sqlSession后手动关闭sqlSession,代码如下:
public void batchInsert(List<TaskCenter> list) {
if(list == null || list.size() == 0){
return;
}
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TaskCenterMapper mapper = sqlSession.getMapper(TaskCenterMapper.class);
for(TaskCenter taskCenter : list){
mapper.insertSelective(taskCenter);
}
sqlSession.flushStatements();
sqlSession.commit();
log.info("批量插入成功: " + list.size()+"条数据");
}catch (Exception ex){
log.error("批量插入失败: ", ex);
}finally {
if (sqlSession != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
}
结语
这篇根据一个生产上的问题通过分析源码了解了MyBatis框架和Spring事务管理自动关闭数据源连接池的功能,了解了原理才好解决问题。
边栏推荐
- kdevelop新建工程
- Data visualization: the four quadrants of data visualization teach you to correctly apply icons
- UE4 remove the mask transparent white edge in the material
- Simplicity studio does not recognize the new JLINK V9 solution
- InvalidConnectionAttributeException异常处理
- Summary of 3DMAX jamming, white screen and rendering crash
- Self cultivation (XXI) servlet life cycle, service method source code analysis, thread safety issues
- 3DMax 卡死、白屏、渲染死机问题总结
- 【华为认证】HCIA-DATACOM史上最全精选题库(附答案解析)
- The difference between cokkie and session
猜你喜欢

Gd32f4xx Ethernet Chip (ENC28J60) Drive transplantation

UE4 去掉材质中Mask透明白边

UE4 在viewport视口中显示3D可编辑点

UE4 blueprint modify get a copy in array to reference

The principle of session and cookie

UE4 animation redirection

In the era of data processing, data quality construction is the way for enterprises to survive

KiCad学习笔记--快捷键

数据可视化:数据可视化四象限,教你正确应用图标

Matlab tips (21) matrix analysis -- partial least squares regression
随机推荐
证券账号开户安全吗?是靠谱的吗?
Go deep into RC, RS, daemonset and statefulset (VII)
Record the field name dynamically modified by SetData of wechat applet
Uber 前安全主管面临欺诈指控,曾隐瞒数据泄露事件
股票炒股账号开户安全吗?是靠谱的吗?
cenos7下搭建LAMP环境
Segmentation of Head and Neck Tumours Using Modified U-net
How to implement observer mode
LSM6DSL之SPI驱动
Student增删gaih
通识篇:原型设计的认知,设计及最佳实践
Idea auto completion
GD32F4xx 以太網芯片(enc28j60)驅動移植
UE4 材质UV纹理不随模型缩放拉伸
Written test question "arrange version numbers from large to small"
Pytorch summary learning series - operation
数据治理:元数据管理(第二篇)
How to do unit test well
367. 有效的完全平方数-二分法
官方stm32芯片包下载地址 stm32f10x stm32f40x下载