问题

  1. 出现abandon connection, owner thread: http-nio-80-exec-19, connected at : 1610323631944, open stackTrace.....错误日志信息
  2. 出现异常nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60004, active 60, maxActive 60, creating 0] with root cause

流程

1. 项目启动时,利用springboot自动装配的原理会加载阿里数据源配置类DruidDataSourceAutoConfigure

public class DruidDataSourceAutoConfigure {private static final Logger LOGGER = LoggerFactory.getLogger(DruidDataSourceAutoConfigure.class);@Bean(initMethod = "init")@ConditionalOnMissingBeanpublic DataSource dataSource() {LOGGER.info("Init DruidDataSource");return new DruidDataSourceWrapper();}
}

DruidDataSourceWrapper继承了DruidDataSource。由于指定了initMethod = “init”,所以spring在创建DruidDataSourceWrapper对象时,会执行DruidDataSourceinit方法。

2. init()初始化

2.1 设置连接池的最大容量

private volatile DruidConnectionHolder[] connections;
.......connections = new DruidConnectionHolder[maxActive];

2.2 init()内的createAndStartCreatorThread()方法

会开一个线程,用来创建连接,并放入DruidConnectionHolder[]中,但线程一开始进入会被阻塞,知道有获取连接的方法执行,再将其唤醒。

2.3 init()内的createAndStartDestroyThread()方法

会开一个定时线程池定时执行扫描。

protected void createAndStartDestroyThread() {destroyTask = new DestroyTask();if (destroyScheduler != null) {long period = timeBetweenEvictionRunsMillis;if (period <= 0) {period = 1000;}destroySchedulerFuture = destroyScheduler.scheduleAtFixedRate(destroyTask, period, period,TimeUnit.MILLISECONDS);initedLatch.countDown();return;}String threadName = "Druid-ConnectionPool-Destroy-" + System.identityHashCode(this);destroyConnectionThread = new DestroyConnectionThread(threadName);destroyConnectionThread.start();
}
public class DestroyTask implements Runnable {@Overridepublic void run() {shrink(true, keepAlive);if (isRemoveAbandoned()) {removeAbandoned();}}}

当配置了removeAbandoned = true,if条件会进入执行removeAbandoned()。

public int removeAbandoned() {int removeCount = 0;long currrentNanos = System.nanoTime();List<DruidPooledConnection> abandonedList = new ArrayList<DruidPooledConnection>();activeConnectionLock.lock();try {Iterator<DruidPooledConnection> iter = activeConnections.keySet().iterator();for (; iter.hasNext();) {DruidPooledConnection pooledConnection = iter.next();if (pooledConnection.isRunning()) {continue;}long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000);if (timeMillis >= removeAbandonedTimeoutMillis) {iter.remove();pooledConnection.setTraceEnable(false);abandonedList.add(pooledConnection);}}} finally {activeConnectionLock.unlock();}if (abandonedList.size() > 0) {for (DruidPooledConnection pooledConnection : abandonedList) {final ReentrantLock lock = pooledConnection.lock;lock.lock();try {if (pooledConnection.isDisable()) {continue;}} finally {lock.unlock();}JdbcUtils.close(pooledConnection);pooledConnection.abandond();removeAbandonedCount++;removeCount++;if (isLogAbandoned()) {StringBuilder buf = new StringBuilder();buf.append("abandon connection, owner thread: ");buf.append(pooledConnection.getOwnerThread().getName());buf.append(", connected at : ");buf.append(pooledConnection.getConnectedTimeMillis());buf.append(", open stackTrace\n");StackTraceElement[] trace = pooledConnection.getConnectStackTrace();for (int i = 0; i < trace.length; i++) {buf.append("\tat ");buf.append(trace[i].toString());buf.append("\n");}buf.append("ownerThread current state is " + pooledConnection.getOwnerThread().getState()+ ", current stackTrace\n");trace = pooledConnection.getOwnerThread().getStackTrace();for (int i = 0; i < trace.length; i++) {buf.append("\tat ");buf.append(trace[i].toString());buf.append("\n");}LOG.error(buf.toString());}}}return removeCount;
}

可以分析出init()执行后,会有个定时线程池每秒执行一次任务,这个任务逻辑是获取活跃连接,判断目前的时间和当时获取连接时的时间相减是否超过了removeAbandonedTimeout配置的时间。超过的话将这个连接从活跃连接中删掉,并加入废弃连接的集合中,如果配置了logAbandoned为true,则打印错误日志:abandon connection, owner thread:…

3. 获取连接

service添加默认事务后,controller调用service方法时,会执行spring的代理方法在开启事务时获取数据源的连接。
DataSourceTransactionManager:

Connection newCon = this.dataSource.getConnection();

这里的dataSource实际为DruidDataSource

getConnection() -> getConnectionInternal()

pollLast(long nanos)

  1. 如果连接池数量poolingCount为0,也就是没有池中没有连接,则:
    执行emptySignal() 将之前init()方法中的createAndStartCreatorThread()创建的创建线程任务从被阻塞转为唤醒,创建连接连接,放入DruidConnectionHolder[]数组中(前提是不要超过maxActive数量)
  2. 如果连接池数量poolingCount仍然后为0,则直接返回null。
  3. 检查从pollLast(long nanos)获取的连接,如果为空,则抛出异常。
if (holder == null) {long waitNanos = waitNanosLocal.get();StringBuilder buf = new StringBuilder();buf.append("wait millis ")//.append(waitNanos / (1000 * 1000))//.append(", active ").append(activeCount)//.append(", maxActive ").append(maxActive)//.append(", creating ").append(creatingCount)//;List<JdbcSqlStatValue> sqlList = this.getDataSourceStat().getRuningSqlList();for (int i = 0; i < sqlList.size(); ++i) {if (i != 0) {buf.append('\n');} else {buf.append(", ");}JdbcSqlStatValue sql = sqlList.get(i);buf.append("runningSqlCount ").append(sql.getRunningCount());buf.append(" : ");buf.append(sql.getSql());}String errorMessage = buf.toString();if (this.createError != null) {throw new GetConnectionTimeoutException(errorMessage, createError);} else {throw new GetConnectionTimeoutException(errorMessage);}
}

解决方案

由以上分析可知,是获取连接执行时间过长导致的。所以在执行时间较长不需要回滚的情况下,使用Propagation.PROPAGATION_NOT_SUPPORTED不使用事务的传播行为配置

注意

  • 要在从controller控制层调用的service方法上使用@Transactional注解,因为事务原理是用aop动态代理。

abandon connection问题分析相关推荐

  1. Druid连接池 报错:abandon connection原因分析

    问题现象: 使用Druid的数据库连接池,在进行一个查询SQL的时候,抛出了异常: [2017-10-20 01:40:59.269 ERROR com.alibaba.druid.pool.Drui ...

  2. com.alibaba.druid.pool.DruidDataSource - abandon connection, open stackTrace

    错误: com.alibaba.druid.pool.DruidDataSource - abandon connection, open stackTrace 原因: 连接池为了防止程序从池里取得连 ...

  3. abandon connection, owner thread: xxxx, connected at : 1606897800625, open stackTrace

    问题现象: 使用Druid的数据库连接池,在进行一个查询SQL的时候,抛出了异常: [2017-10-20 01:40:59.269 ERROR com.alibaba.druid.pool.Drui ...

  4. Druid连接池一个设置引发的血案【abandon connection, open stackTrace】

    2019独角兽企业重金招聘Python工程师标准>>> 今天在一台配置很低的机器上运行批量更新的程序~~~ 大概跑了三十分钟~~~这配置~~~这程序~~~ 然后华丽丽的报异常了~~~ ...

  5. ERROR com.alibaba.druid.pool.DruidDataSource - abandon connection, open stackTrace: 已解决

    错误日志: 2020-07-13 15:37:58,545 [Druid-ConnectionPool-Destroy-2092318840] ERROR com.alibaba.druid.pool ...

  6. abandon connection报错连接池问题

    abandon connection 报错来自于DruidDataSource这个类,根据报错的信息,可以看出是因为执行SQL时获取不到Connection连接,然后去看一下Druid的配置中,有三个 ...

  7. mysql no connections_mysql数据库NO CONNECTION问题分析以及解决方案

    自己的站点有时候会挂掉,着实比较麻烦,我不会24小时都看着,说多的都是泪 出现mysql出现NO CONNECTION 有可能原因:mysql服务出现问题 解决方案:重启mysql服务,数据库就连接上 ...

  8. RabbitMQ connection.CreateModel() 分析

  9. connection holder is null

    1 连接被回收 (1)错误日志 Caused by: java.sql.SQLException: connection holder is null at com.alibaba.druid.poo ...

  10. 瞬发大量并发连接 造成MySQL连接不响应的分析

    http://www.actionsky.com/docs/archives/252  2016年12月7日  黄炎 目录 1 现象 2 猜想 3 检查环境 4 猜想2 5 分析 5.1 TCP握手的 ...

最新文章

  1. 【组队学习】【33期】动手学数据分析
  2. 【SpringCloud】Zuul-实例
  3. python爬虫用urllib还是reques,python爬虫中urllib.request和requests有什么区别?
  4. python初学工资-python工资高还是java?
  5. Django资源大全
  6. 传递参数命令——xargs
  7. go get github.com/astaxie/beego 没有反应
  8. 使用 CSS 用户选择控制选择
  9. IE8,9下的ajax缓存问题
  10. Spring注解实现aop
  11. 【运输量预测】基于matlab多种算法公路运输量预测【含Matlab源码 041期】
  12. api 文件长度_上传下载API
  13. docker学习笔记3:镜像操作(查找和下载)
  14. 高质量程序设计指南C++/C试题
  15. uiso9|uiso9_cn.exe
  16. PCWorld:HTML5会终结移动应用程序吗?
  17. 网易博客搬家至CSDN博客指南
  18. 中国通信简史 (下)
  19. Linux如何终止D状态的进程
  20. 文创雪糕火出圈!是真内卷还是真搞笑?

热门文章

  1. Scratch编程(十)扩展模块:视频侦测模块
  2. python中reduce函数_reduce函数
  3. 全球及中国智能家居设备市场竞争态势与投资策略建议报告2022版
  4. 误差条图各部分的代表意思_【小强视界】混凝土搅拌站计量误差原因分析及控制措施...
  5. 基于MySQL毕业设计题目50例
  6. c语言航标知识点,书摘:迷惘时的航标——“人生哲学”
  7. 学校计算机怎么连接自己的热点,笔记本电脑怎么连接手机热点(手机热点开启及连接方法)...
  8. 使用IDEA工具远程调试SpringBoot应用
  9. 设备屏幕亮度调节代码实现
  10. 程序员之网络安全系列