alibaba / druid

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

breakAfterAcquireFailure为true时, 数据库连接只要失败一次, 之后就一直失败(即使数据库连接已经恢复正常) #2862

Open chenxi-null opened 5 years ago

chenxi-null commented 5 years ago

数据库连接只要失败一次, 之后就一直失败, 日志打印的错误堆栈都是相同的,一直在"重复"一开始的错误, 即使此时数据库连接已经恢复正常, 导致应用无法连接数据库,除非重启应用才会恢复正常.

这个情况在开发和测试环境都出现过几次, 在本地也可以稳定重现, 重现方式:关闭再开启数据库.

环境: SpringBoot: 2.0.3.RELEASE, druid-spring-boot-starter: 1.1.10

数据库: MySQL

配置文件:

# DataSource
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://***/***?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=***
spring.datasource.password=***

# JPA
spring.jpa.database=MYSQL
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

# Database Connection Pool (Druid)
spring.datasource.druid.initialSize=5
spring.datasource.druid.minIdle=5
spring.datasource.druid.maxActive=20
spring.datasource.druid.maxWait=8000
spring.datasource.druid.breakAfterAcquireFailure=true
spring.datasource.druid.timeBetweenEvictionRunsMillis=60000
spring.datasource.druid.minEvictableIdleTimeMillis=300000
spring.datasource.druid.validationQuery=SELECT 'x'
spring.datasource.druid.testWhileIdle=true
spring.datasource.druid.poolPreparedStatements=true
spring.datasource.druid.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.druid.filters=stat,wall,slf4j
spring.datasource.druid.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
spring.datasource.druid.stat-view-servlet.login-username=***
spring.datasource.druid.stat-view-servlet.login-password=***
yinxiaoling commented 5 years ago

这个属性我都找不到,换了好几个版本,无线重连直接把服务器干爆了,这问题都没人管管。

leafV commented 5 years ago

breakAfterAcquireFailure=true导致应用无法连接数据库,除非重启。connectionErrorRetryAttempts默认值1,从源码和自测日志看,应该是失败connectionErrorRetryAttempts+1次(默认2次),就无法连接数据库。源码: DruidDataSource->CreateConnectionThread->run()方法。

BongBongBang commented 5 years ago

druid version:1.1.20

同样发现了这个问题,数据源一直在报connect error。搜了文档也没找到官方介绍这个breakAfterAcquireFailure参数的地方。 再一个有个疑问:Druid在统计建立连接的错误次数后,代码逻辑为什么是在错误次数超过一个阈值(connectionErrorRetryAttempts)的时候就进行继续重连的逻辑?不应该是反过来吗?

BongBongBang commented 5 years ago

父类DruidAbstractDataSource里倒是有breakxx这个参数的相应setter方法,就调用方法吧。

xcjm820 commented 3 years ago

所以现在是需要手动检测下状态自己设置breakAfterAcquireFailure值吗?新版本有修复吗

FayeSpica commented 2 years ago

2022年了,似乎还是有问题

FayeSpica commented 2 years ago

CreateConnectionThread 在设置了breakAfterAcquireFailure=true之后就终止了,只要失败了,这个线程就死掉了,所以getConnection没用

FayeSpica commented 2 years ago

解决办法也很简单,设置使用自定的scheduler去创建connection就行了:

ScheduledExecutorService createScheduler = Executors.newScheduledThreadPool(4);
ScheduledExecutorService destroyScheduler = Executors.newScheduledThreadPool(4);

druidDataSource.setBreakAfterAcquireFailure(true);
druidDataSource.setCreateScheduler(createScheduler);
druidDataSource.setDestroyScheduler(destroyScheduler);