Could not open JDBC Connection for transaction; nested exception is com.alibaba.druid.pool.DataSourc

2年前 (2022) 程序员胖胖胖虎阿
431 0 0

一、错误概述

项目中使用了阿里的 Druid 数据库,刚开始很正常,后来发现出现了问题,问题如下:

org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is com.alibaba.druid.pool.DataSourceClosedException: dataSource already closed at Fri Jul 08 16:14:13 GMT+08:00 2022
    at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:309)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:400)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:595)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:382)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)
    at java.base/java.util.TimerThread.mainLoop(Timer.java:566)
    at java.base/java.util.TimerThread.run(Timer.java:516)
Caused by: com.alibaba.druid.pool.DataSourceClosedException: dataSource already closed at Fri Jul 08 16:14:13 GMT+08:00 2022
    at com.alibaba.druid.pool.DruidDataSource.getConnectionInternal(DruidDataSource.java:1113)
    at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:1017)
    at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:997)
    at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:987)
    at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:103)
    at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:265)
    ... 13 common frames omitted

 日志比较多,重点有以下几个:

Could not open JDBC Connection for transaction; nested exception is com.alibaba.druid.pool.DataSourceClosedException: dataSource already closed at Fri Jul 08 16:14:13 GMT+08:00 2022

 Caused by: com.alibaba.druid.pool.DataSourceClosedException: dataSource already closed at Fri Jul 08 16:14:13 GMT+08:00 2022

 其他的我们截图看看:

Could not open JDBC Connection for transaction; nested exception is com.alibaba.druid.pool.DataSourc

 上图打码的地方是公司的dao层查数据库的代码。

意思很明白了,就是因为在进行查询的时候,连接已经关闭了,而且会一直刷出这样的日志。

二、网友的给出的原因与解决方案

综合网上大家的意见,可能原因主要有以下几点:

1.异步线程问题

你可能使用了异步线程去访问数据库,异步线程是不由spring管理也就是说,spring可以在异步线程未执行完就会进行容器关闭 当异步线程执行到获取数据库的时候就会报错

 博主给的答案是:

怎么才能彻底消除这个错误没有找到完美的解决方法,只要DataSource不进行重新注册,或者重新注册后再刷新相关的DAO引用的实例可暂时不出现这个问题了

 参考:Druid连接池自动关闭

2.多线程批量问题

其实这个答案和上面一个的说法一致,不过这个给出了解决方案:

 多线程批量处理的时候只需要在service方法上加上@transactional(rollbackFor = Exception.class)就行了,mybatis就不会每次执行完sql后closing sql session了

3. 热部署问题

是否在定时器中手动获取了 DataSource,然后使用后关闭了或者用完后长期不再用被连接池自动关闭了?

答案是:发现不修改代码的时候,不会发生异常,修改代码之后触发热加载,然后就中断了链接,所以就报出那个错误。

这是网友的答案。

4.自动关闭问题

应该就是长时间不用,Druid自动关闭的问题。

这也是网友给出的可能性答案。

下面的也是网友的答案:

如果使用 jfinal 提供的 ActiveRecord 或者 Db + Record 操作数据库就不会出现此问题,自行得到 DataSource 或 Connection 的代码就需要开发者自己管理好这两个对象。

这个我没有尝试。

.setTestOnBorrow(false)
.setTestOnReturn(false)

都改成 true。有网友说这个答案。

我试了试,没有什么卵用。

三、我的错误原因

最终我发现可能的原因是:

我这项目启动的时候会有 @PostConstruct 注解初始化 redis 数据,通过多线程方式去处理,然后还会有定时任务定时刷新。而项目中有热部署,只要改动代码之后就会自动重启项目,然后就会出现了上述的错误。

如果我改动了代码,不让它热部署启动,我手动重启,或者先关闭项目然后再启动,就不会报这个错误了。

所以,我这边最终的原因就是热部署的问题,我的热部署不是使用的devtools,而是idea上有一个配置,改动配置之后就会热部署,但是我忘记改动哪个地方了。以后想起来了,再来修改文章。

四、奇怪的问题

我们同一套代码,都是Git上最新代码,但是我同事的代码就会报上面这个错误,我的就好的,他的没有热部署。最终发现的原因竟然是:

package com.xxx.common.util;

import com.xxx.common.file.SftpAuthority;
import com.xxx.ytec.common.file.SftpService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(1)
public class FileCommandLineRunner implements CommandLineRunner {

    private static final Logger LOGGER = LoggerFactory.getLogger(FileCommandLineRunner.class);

    @Autowired
    private SftpService sftpService;

    @Override
    public void run(String... args) throws Exception {
        LOGGER.info("---------FileCommandLineRunner下载文件开始---------");

        SftpAuthority root = new SftpAuthority("root", "192.168.0.100", 22);
        root.setPassword("123456");
        sftpService.createChannel(root);
        sftpService.downloadFile(root, "/xxx/file/Data.csv", "C:\\Users\\Data.csv");
        LOGGER.info("---------FileCommandLineRunner下载文件成功---------");
    }
}

 因为这一套代码,他那里报了我们上面说的错,这个代码怎么与数据源连接有关呢?这个代码就是在项目启动的时候自动执行里面的代码,里面的逻辑就是通过sftp从服务器上下载文件的。

现在他的报错如下:

Could not open JDBC Connection for transaction; nested exception is com.alibaba.druid.pool.DataSourc

 这个问题是很奇怪的,在我的电脑上没问题,在他那就会报错,只好把这个代码注释掉了。本来这个代码是我写给他测试下载文件的,也不会用到。

问题不算完美解决,暂时先这样吧!

相关文章

暂无评论

暂无评论...