Hikaricp: HikariDataSource throws no sql-exceptions

Created on 8 Dec 2016  路  7Comments  路  Source: brettwooldridge/HikariCP

When I try to invoke HikariDataSource.getConnection() I get HikariPool.PoolInitializationException that doesn't extend SqlException

I think this exception should extend SqlException too
Trace:
`` Exception in thread "vertx-jdbc-service-get-connection-thread" com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: Access denied for user '****'@'localhost' (using password: YES) at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:512) at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:105) at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:94) at io.vertx.ext.jdbc.impl.JDBCClientImpl.lambda$getConnection$1(JDBCClientImpl.java:124) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: java.sql.SQLException: Access denied for user '***'@'localhost' (using password: YES) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:964) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3970) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3906) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:873) at com.mysql.jdbc.MysqlIO.proceedHandshakeWithPluggableAuthentication(MysqlIO.java:1710) at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1226) at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2253) at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2284) at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2083) at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:806) at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:410) at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:328) at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:95) at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:101) at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:341) at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:506) ... 6 more

All 7 comments

@brettwooldridge Any thoughts on having checkFailFast throw a SQLException instead of a RuntimeException ?

Its trying to establish a database connection via getConnection() which is failing with a SQLException which should be propagated IMO

@AlmazKo @kevinconaway The trouble is that checkFailFast() is called from the HikariPool constructor, and that constructor can be called either from HikariDataSource.getConnection() (lazy initialization) or when HikariDataSource is constructed. Changing checkFailFast() to throw a checked exception rather than a runtime exception would mean that one of the HikariDataSource constructors would need to throw a SQLException but not the other. That change would also alter the ABI (application binary interface), which would break existing code that is not written to catch it.

The best we could do would be to catch PoolInitializationException in HikariDataSource.getConnection(), dig out the SQLException inside and re-throw that.

I figured as much. Would you mind sharing the logic behind the fail fast check in the first place? My personal expectation would be that the data source wouldn't connect to the database until I ask it to (via getConnection()), not when I'm creating the DataSource itself.

Would another option be to make this behavior configurable? That might be against the ethos of the project though from what I'm read (limiting the number of knobs to turn)

@kevinconaway Many users (possibly most) want to know if they have specified incorrect connection parameters right away -- at pool startup -- rather than later when getConnection() is called. If the connection parameters are incorrect, for example an invalid username, then the pool will never be able to create a connection.

This "fail fast" behavior can be disabled by setting initializationFailFast=false.

This "fail fast" behavior can be disabled by setting initializationFailFast=false.

Thanks Brett, I missed that in the documentation.

The case I'm interested in is being able to start while the database is currently down (and eventually connect), not that my connection parameters are incorrect

Cheers

@kevinconaway Yes. Once you are sure that your connection parameters are correct, you can set initializationFailFast to false and the pool will start even though the database is currently down. HikariCP will continue to make connection attempts to the database every 2 seconds or so in the background.

Actually, in release 2.5.2 (coming shortly), the initializationFailFast property has been deprecated, and is being replaced by initializationFailTimeout. You can try 2.5.2-SNAPSHOT if you are interested, details here.

The JavaDoc for initializationFailTimeout states:

Any value less than zero will not block the calling thread in the case
that a connection cannot be obtained. The pool will start and
and continue to try to obtain connections in the background. This can
mean that callers to DataSource.getConnection() may encounter
exceptions.

Any value greater than or equal to zero will be treated as a timeout for
pool initialization. The calling thread will be blocked from continuing
until a successful connection to the database, or until the timeout is
reached. If the timeout is reached, then a PoolInitializationException
will be thrown.

Note that this timeout does not override the connectionTimeout or
validationTimeout; they will be honored before this timeout is applied.

@AlmazKo @kevinconaway The "lazy" pool construction path, called when HikariDataSource is constructed with the no-arg constructor and getConnection() is called, will now catch the PoolInitializationException and throw the contained SQLException. If the driver itself throws something other than a SQLException then the PoolInitializationException will still be thrown.

Was this page helpful?
0 / 5 - 0 ratings