alibaba / druid

阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品,为监控而生的数据库连接池
https://github.com/alibaba/druid/wiki
Apache License 2.0
27.97k stars 8.58k forks source link

事务未提交 连接关闭 提示connection holder is null #4693

Open saikonwu opened 2 years ago

saikonwu commented 2 years ago

版本 1.1.9 连接池最大最小设置 1 个 removeabndoned设置true removeAbandonedTimeout设置10s 开启事务后不提交

DefaultTransactionDefinition definition = TransationUtil.getTransationDefinition();
TransactionStatus transactionStatus = txManager.getTransaction(definition);
String complainNo = "20210123421321";
String modelComplainNo = "20210123421321";
dao.synchronizeComplainBase(complainNo, modelComplainNo);
{
    Thread.sleep(60000);
} (InterruptedException e) {
    e.printStackTrace();
}
dao.synchronizeComplainInfo(complainNo, modelComplainNo);
dao.synchronizeComplainantInfo(complainNo, modelComplainNo);
dao.synchronizeComplainTarget(complainNo, modelComplainNo);

后续再次获取连接任意数据库操作都会提示: `Caused by: java.sql.SQLException: connection holder is null

at com.alibaba.druid.pool.DruidPooledConnection.checkStateInternal(DruidPooledConnection.java:1157)

at com.alibaba.druid.pool.DruidPooledConnection.checkState(DruidPooledConnection.java:1148)

at com.alibaba.druid.pool.DruidPooledConnection.getAutoCommit(DruidPooledConnection.java:736)

at org.mybatis.spring.transaction.SpringManagedTransaction.openConnection(SpringManagedTransaction.java:81)

at org.mybatis.spring.transaction.SpringManagedTransaction.getConnection(SpringManagedTransaction.java:67)

at org.apache.ibatis.executor.BaseExecutor.getConnection(BaseExecutor.java:337)

at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:86)

at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:49)

at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)

at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)

at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197)

... 17 more`
SoledadVac commented 2 years ago

时间过长,连接被回收了

saikonwu commented 2 years ago

时间过长,连接被回收了 可是连接被回收之后,为何其他线程获取到该连接是不可用的;连接回收了应该保证其是正常连接

zrlw commented 2 years ago

应该是shrink不应该采用System.arrayCopy前移方式清理connections数组的问题,可以看看 https://github.com/alibaba/druid/issues/4692

liuyandeng commented 5 months ago

我也有出现,怎么解决呢,#5920

4fool commented 5 months ago

时间过长,连接被回收了 可是连接被回收之后,为何其他线程获取到该连接是不可用的;连接回收了应该保证其是正常连接

针对这个示例,大概过程是这样的:

  1. dao.synchronizeComplainBase(complainNo, modelComplainNo);会从连接池中获取一个DruidPooledConnection的实例(为方便表达这个实例用001表示);
  2. Thread.sleep(60000);过程中,由于removeabndoned设置true,removeAbandonedTimeout设置10s,期间大概率执行了DestroyTask中的removeAbandoned(),进而调用了DruidPooledConnection.close(),在close()方法中会将holder设置为null,且不会将001这个实例放回连接池;
  3. 在执行dao.synchronizeComplainInfo(complainNo, modelComplainNo);的时候,会从Spring线程局部变量中获取到001实例。在执行操作(增删改查等)之前都会调用DruidPooledConnection.checkState进行状态检测,由于001实例的holder==null,所以抛出了上面的异常。
liuyandeng commented 5 months ago

时间过长,连接被回收了 可是连接被回收之后,为何其他线程获取到该连接是不可用的;连接回收了应该保证其是正常连接

针对这个示例,大概过程是这样的:

  1. dao.synchronizeComplainBase(complainNo, modelComplainNo);会从连接池中获取一个DruidPooledConnection的实例(为方便表达这个实例用001表示);
  2. Thread.sleep(60000);过程中,由于removeabndoned设置true,removeAbandonedTimeout设置10s,期间大概率执行了DestroyTask中的removeAbandoned(),进而调用了DruidPooledConnection.close(),在close()方法中会将holder设置为null,且不会将001这个实例放回连接池;
  3. 在执行dao.synchronizeComplainInfo(complainNo, modelComplainNo);的时候,会从Spring线程局部变量中获取到001实例。在执行操作(增删改查等)之前都会调用DruidPooledConnection.checkState进行状态检测,由于001实例的holder==null,所以抛出了上面的异常。

请看下#5920,我没配置removeabndoned