美文网首页
REQUIRES_NEW导致数据库连接死锁

REQUIRES_NEW导致数据库连接死锁

作者: 十毛tenmao | 来源:发表于2019-07-17 23:38 被阅读0次

    在项目中,我们使用Spring事务传播类型REQUIRES_NEW实现了子事务的独立性,但是在高并发的情况下出现了数据库连接获取不到的问题

    问题症状

    当出现较大并发访问系统时,比如30并发,则会出现以下错误

    CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLTransientConnectionException: HikariPool1 - Connection is not available, request timed out after 30000ms.
    

    获取数据库连接的时间居然超过了30秒,正常情况下一个请求的处理时间是200ms,所以觉得特别奇怪。 按说即使数据库连接数小于请求并发数,因为数据库连接是共享的,请求也可以很快地获取到数据库连接并完成请求。但是实际却超过了30秒。

    查看连接池情况

    • 从连接池信息可以看出,当请求并发量很大时,连接数确实不够。而且最大连接数已经是100(默认是10)
    HikariPool1 - Before cleanup stats (total=22, active=0, idle=22, waiting=0)
    HikariPool1 - Before cleanup stats (total=49, active=49, idle=0, waiting=87)
    oikariPool1 - Before cleanup stats (total=100, active=100, idle=0, waiting=70)
    HikariPool1 - Before cleanup stats (total=100, active=0, idle=100, waiting=0)
    HikariPool1 - Before cleanup stats (total=100, active=0, idle=100, waiting=0)
    

    查看日志,觉得更加奇怪了,请求并发数是30,连接数已经是100了,但是还是不够。 所以怀疑连接泄漏了。但是使用的Spring Boot来管理连接池,并不是手动使用连接池,应该不可能是泄漏了。

    查看请求日志

    • 查看一个请求中数据库连接相关的日志
    Acquired Connection [HikariProxyConnection@880338874 wrapping com.mysql.cj.jdbc.ConnectionImpl@332c8129] for JDBC transaction
    Switching JDBC Connection [HikariProxyConnection@880338874 wrapping com.mysql.cj.jdbc.ConnectionImpl@332c8129] to manual commit
    ...
    Transaction synchronization suspending SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@726cda03]
    Acquired Connection [HikariProxyConnection@1154774545 wrapping com.mysql.cj.jdbc.ConnectionImpl@4664e639] for JDBC transaction
    Switching JDBC Connection [HikariProxyConnection@1154774545 wrapping com.mysql.cj.jdbc.ConnectionImpl@4664e639] to manual commit
    
    ...
    Transaction synchronization suspending SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@571ff6bc]
    Acquired Connection [HikariProxyConnection@356317124 wrapping com.mysql.cj.jdbc.ConnectionImpl@1e0e3cb5] for JDBC transaction
    Switching JDBC Connection [HikariProxyConnection@356317124 wrapping com.mysql.cj.jdbc.ConnectionImpl@1e0e3cb5] to manual commit
    

    从这个日志中Transaction synchronization suspending SqlSession可以看到,因为使用Spring事务的REQUIRES_NEW传播类型,导致一个请求会同时占用多个连接,没有释放。这样就可能导致获取连接的死锁

    解决办法

    • 设置连接超时时间,当获取连接的时间超过阈值时,就会退出事务,释放事务占用的连接。这样就可以破坏死锁条件spring.datasource.hikari.connection-timeout: 3000

    参考

    相关文章

      网友评论

          本文标题:REQUIRES_NEW导致数据库连接死锁

          本文链接:https://www.haomeiwen.com/subject/mhlhlctx.html