alibaba / druid

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

CommunicationsException with spring boot health check #3441

Open huangxfchn opened 5 years ago

huangxfchn commented 5 years ago

Description

public class DataSourceHealthIndicator extends AbstractHealthIndicator implements InitializingBean {
    private void doDataSourceHealthCheck(Health.Builder builder) throws Exception {
        String product = getProduct();
        builder.up().withDetail("database", product);
        String validationQuery = getValidationQuery(product);
        // execute validationQuery……
     }

    private String getProduct() {
        return this.jdbcTemplate.execute((ConnectionCallback<String>) this::getProduct);
    }

    private String getProduct(Connection connection) throws SQLException {
        return connection.getMetaData().getDatabaseProductName();
    }
}

Exception analysis

The spring boot actuator gets the jdbc Connection when executing the DataSource health check, and calls connection.getMetaData().getDatabaseProductName(), which does not actually operate the database, resulting in the connection's effective time not being renewal.

When returning to the connection pool, Druid will change lastActiveTimeMillis to the latest time, which will cause the cleanup thread to mistake the connection for its validity, so it has not been cleaned up.

In fact, it has passed the survival time. It will disturb the cleanup of the connection pool, then the next time you get this connection, it will be invalid for MySql, throwing a CommunicationsException exception.

If I just get the connection from the connection pool and return it to the connection pool, nothing is done. This will also update the time of 'lastActiveTimeMillis', which will disturb the recycling thread to determine whether the connection is invalid or not.

huangxfchn commented 5 years ago

@wenshao