开发者社区> 问答> 正文

DruidDataSource restart()导致CreateConnectionThread退

版本: druid-1.2.5 问题: 本人项目使用druid+sqlite, 运行过程需要重启DruidDataSource, 使用的时候发现restart DruidDataSource后出现 Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 20000, active 0, maxActive 40, creating 0 重启代码为((DruidDataSource)readDataSource).restart(); 个人分析: 查看源码, restart()中调用close()

public void restart() throws SQLException { lock.lock(); try { if (activeCount > 0) { throw new SQLException("can not restart, activeCount not zero. " + activeCount); } if (LOG.isInfoEnabled()) { LOG.info("{dataSource-" + this.getID() + "} restart"); }

    this.close();
    this.resetStat();
    this.inited = false;
    this.enable = true;
    this.closed = false;
} finally {
    lock.unlock();
}

}

close()中将closing变量置为true, 其中closing默认初始化为false

public void close() { if (LOG.isInfoEnabled()) { LOG.info("{dataSource-" + this.getID() + "} closing ..."); }

lock.lock();
try {
    if (this.closed) {
        return;
    }

    if (!this.inited) {
        return;
    }

    this.closing = true;
    ...
    this.closed = true;
    ...
} finally {
    lock.unlock();
}
...

}

在之后的init中或者其他位置, 并没有将closing重新置为false

public void init() throws SQLException { ... boolean init = false; try { ... createAndLogThread(); createAndStartCreatorThread(); # 创建启动CreateConnectionThread线程 createAndStartDestroyThread(); ... } catch (SQLException e) { ... } }

在restart()后创建的CreateConnectionThread线程中, 创建一次连接后由于closing为true会导致线程退出, 后续无法再通过empty信号量触发创建新的连接, 最终触发超时异常.

public class CreateConnectionThread extends Thread { public void run() { ... for (;;) { ...

        boolean result = put(connection);
        if (!result) {
            JdbcUtils.close(connection.getPhysicalConnection());
            LOG.info("put physical connection to pool failed.");
        }

        errorCount = 0; // reset errorCount

        if (closing || closed) {
            break;
        }
    }
}

}

测试通过反射在restart()后, 将closing变量改为false, 超时问题消失.

原提问者GitHub用户ribribrib2

展开
收起
山海行 2023-07-05 18:02:56 217 0
2 条回答
写回答
取消 提交回答
  • 北京阿里云ACE会长

    DruidDataSource 的 restart() 方法会关闭当前数据源,并重新初始化一个新的数据源,因此会导致所有的数据库连接被关闭。在关闭连接的过程中,会涉及到关闭连接的线程,其中包括 CreateConnectionThread 线程。如果在关闭连接的过程中,CreateConnectionThread 线程正在运行,它可能会尝试使用已经关闭的连接来创建新的连接,从而抛出异常并退出线程。
    为了避免这个问题,您可以在调用 restart() 方法之前,先停止所有的数据库连接。

    2023-07-30 20:52:21
    赞同 展开评论 打赏
  • 发现1.2.6版本添加了closing=false的赋值

    https://blog.51cto.com/iteyer/3237594

    原回答者GitHub用户ribribrib2

    2023-07-06 10:42:10
    赞同 展开评论 打赏
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载