To add a bit more context on why i ask this. We have noticed that in our database there are a lot of select 1 from dual queries. which is neither a heavy query or bad..but do we really need to run a query to validate the datasource?

isn't a simple (with the reasonable try-catch blocks of-course)

datasource.getConnections().close();

enough?

or for extra validation

datasource.getConnections().isValid();

both the above 2 approaches will result in the same behaviour as the existing one with better timeout handing in some jdbc drivers (for example for oracle). Besides, all datasource pools, are already doing validation according to their configs in an optimal way.

for example have a look at micronaut's health indicator

single simple file, database agnostic.

I believe this will simplify a lot the health check, and dba's around the world will be happy as well

If the community does not feel comfortable enough with jdbc driver validation mechanisms in general ( i don't see why not) , maybe we could add a property to control whether datasourceHelathIndicatorshould run a query, or rely on the jdbc driver isValid method.

besides, this looks like a double config problem, we specify in one place how hikari (personally i chose the isValid method of the jdbc driver) validates, and then there is the datasourceHealthIndicator which is overriding this validation scheme.

this probably fixes: https://github.com/spring-projects/spring-boot/issues/4391 . At least for oracle, as in oracle drivers, the connection.isValid() respects the timeout that is configured in the pool. Probably same applies in other jdbc drivers

Comment From: wilkinsona

both the above 2 approaches will result in the same behaviour as the existing one

This would not result in the same behaviour. For example, we know that we have users that are using a custom query to meet their interpretation of what it means for the DataSource to be healthy.

besides, this looks like a double config problem, we specify in one place how hikari (personally i chose the isValid method of the jdbc driver) validates, and then there is the datasourceHealthIndicator which is overriding this validation scheme.

Let's consider providing an option to use isValid() in the health indicator. That should satisfy both use cases.

Comment From: ckoutsouridis

Thank you @wilkinsona. i would suggest to use the hikariCP approach.

In hikariCP if we don't specify a connection-test-query, the validation will be done against the connection.isValid() of the jdbc driver .

in the same way, if someone is not specifying a custom query for the healthIndicator, maybe it's better to just use the isValid().

Besides, if it's not a custom query the isValid and select 1 from * are kind of equivalent.

We should also keep in mind that if we configure the datasource with something like spring.datasource.hikari.connection-test-query=test_my_db_query

Apart from some minor timing windows, this query will get executed by a simple datasource.getConnection()

Comment From: wilkinsona

Apart from some minor timing windows, this query will get executed by a simple datasource.getConnection()

We cannot be certain that is the case if the DataSource has been proxied. It's possible for a Connection returned from DataSource.getConnection() to be lazy and only actually retrieve a Connection from the pool when it's used.

Comment From: ckoutsouridis

interesting, well, i am not sure how all datasource pools work, but at lest for hikaricp, the pool will not release a connection unless it passes the validation stage (according to it's ALIVE_BYPASS_WINDOW_MS).

So with a default setup, if a connection is not used within 500ms, the connection validation will run just by a datasource.getConnection()

in fact, after debugging this, the pool validation query is executed by the healthIndicator, even before the check query, it is executed during this block:

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

In any case, any improvement in this, would be welcome.

Comment From: ttddyy

+1 for using isValid() on DataSourceHealthIndicator.

Currently, in our tracing, there are bunch of SELECT 1 traces. So, we need to exclude SELECT 1 on tracing configuration for jdbc instrumentation. Such traces affect rate limit/capacity for the tracing service.

I like the idea that if test query is specified, then use the query; otherwise use isValid. Though, it wouldn't really match with current design which retrieves default validation query from DatabaseDriver#validationQuery when query is not specified.

According to hikari documentation:

connectionTestQuery If your driver supports JDBC4 we strongly recommend not setting this property. This is for "legacy" drivers that do not support the JDBC4 Connection.isValid() API. ...

We introduced similar in R2DBC-SPI, Connection#validate. This is because driver knows better in current condition of the connection, and it may have internal optimal way to check the status of the connection rather than performing validation query.

Comment From: snicoll

I've started to hack something and, given the different in behaviour, I am wondering if that wouldn't be better to have a completely separate implementation (see 89c73bc). Using Connection#isValid is very simple, does not require spring-jdbc on the classpath (as there is no need for JdbcTemplate) and mixing the two modes in the same implementation feels a bit confusing to me.