博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
druid数据库连接池问题:java.sql.SQLException: connection holder is null
阅读量:6898 次
发布时间:2019-06-27

本文共 2764 字,大约阅读时间需要 9 分钟。

hot3.png

项目中使用了/数据库连接池,但是发现运行着一段时间后,总会报

java.sql.SQLException: connection holder is null

查阅很多解决办法都说设置。

这两个参数就可以了,但我的项目里,并不是这种超时间使用连接没有回收而导致的,所以这种解决方法并不能解决我的问题。

而且druid版本已经是1.1.2最新的版本,排除了druid非bug原因,那就是我本身项目代码问题了。

在druid官方github问题里也有很多同学的发现问题发析原因,顿时有了思路。

参考连接:  、。

两个问题都指出跨线程使用druid而引发的,温少也建议不要跨线程使用数据连接。

所以经过两天的查资料,和不断地尝试,终于找出问题所在。

首先我的项目里是用了spring-boot,连接池配置这些就不贴出来了,都大同小异。

而我的事务管理也是用的是spring的 @Transactional 注入管理。

问题在于,我的一个service方法里的一个方法里,该方法在事务提交之后,会再次触发另一个service执行代码。

@Service@Transactional(value = "transaction", rollbackFor = Exception.class)public class a_service {        @Autowired    private Dao dao;    @Autowired    private ApplicationEventPublisher publisher;        /**     *该方法执行所有代码之后,会触发publisher.publishEvent方法     */    public String test(){        .....省略执行代码.....                publisher.publishEvent(params);    }}@Service@Transactional(value = "transaction", rollbackFor = Exception.class)public class b_service {    @Autowired    private Dao dao;        /**     * 当事务提交后, 才会真正的执行@TransactionalEventListener配置的Listener, 如果Listener抛异常, 方法返回失     * 败, 但事务不会回滚.     */    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)    public String test(){        dao.save(params);    }}

 

问题就出于 b_service执行这里,当触发b_service方法时,b_service的事务隔离级别是默认PROPAGATION_REQUIRED,即如果当前存在事务则加入该事务

PROPAGATION_REQUIRED

加入当前正要执行的事务不在另外一个事务里,那么就起一个新的事务
比如说,ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于执行ServiceA.methodA的时候,
ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,ServiceB.methodB看到自己已经运行在ServiceA.methodA
的事务内部,就不再起新的事务。而假如ServiceA.methodA运行的时候发现自己没有在事务中,他就会为自己分配一个事务。
这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚。即使ServiceB.methodB的事务已经被
提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚

由于b_service方法事务监听a_service方法,a_service的连接提交事务后就回收到连接池中,b_service获取方法运行完之后归还连接,b_service获取的连接可能是a_service的准备归返的连接,所以就造成跨线程使用链接问题

解决方法就是在b_service 事务管理设置事务级别 propagation = Propagation.REQUIRES_NEW

@Service@Transactional(value = "transaction", propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)public class b_service {    @Autowired    private Dao dao;        /**     * 当事务提交后, 才会真正的执行@TransactionalEventListener配置的Listener, 如果Listener抛异常, 方法返回失     * 败, 但事务不会回滚.     */    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)    public String test(){        dao.save(params);    }}

参考资料

https://github.com/alibaba/druid/issues/1429

https://github.com/alibaba/druid/issues/1889

http://timerbin.iteye.com/blog/2332995

https://my.oschina.net/haogrgr/blog/224010

 

ps:

@TransactionalEventListener, 可以方便在事务周期内处理一些事情, 比如事务提交后触发某一事件.

    一个场景就是, 当插入记录提交事务后, 异步发送消息到其他系统, 或本地记录日志等操作, 现在可以通过TransactionalEventListener来做了. 

上面的文字解释可能表达得不太好,也有些歧意,如果有更好见解,可以联系私信本人,谢谢

转载于:https://my.oschina.net/u/1789379/blog/1506450

你可能感兴趣的文章
云数据库产品月刊·5月刊
查看>>
50行代码的MVVM,感受闭包的艺术
查看>>
Android第三方开源图片裁剪截取:cropper
查看>>
直播转点播实践
查看>>
基于Java语言构建区块链(二)—— 工作量证明
查看>>
Python黑科技:50行代码运用Python+OpenCV实现人脸追踪
查看>>
获取高德地图的四级地址
查看>>
图像识别落地B端应用,商业化的“绣球”先抛给了哪些行业?
查看>>
Elasticsearch结构化搜索_在案例中实战使用term filter来搜索数据
查看>>
Eclipse在Project Explorer项目归组及分模块显示
查看>>
超全总结:神经网络加速之量化模型 | 附带代码
查看>>
批量将xml文件转json并写入文件
查看>>
python web开发之——Flask入门教程
查看>>
区块链每日一问 | 什么是区块链的“分叉”?
查看>>
Java并发编程之CountDownLatch
查看>>
AI版本的AK-47或问世,可以在无人操控下自主决定射击
查看>>
Bootstrap学习笔记--表格
查看>>
JVM内存区域与多线程
查看>>
光谱响应与量子效率
查看>>
Tcp创建三次握手和关闭四次握手
查看>>