Can't use Hibernate with MySQL server 8, HikariCP enabled


#1

Hibernate version: 5.3.7.Final
HikariCP version: 3.2.0
MySQL connector version: 8.0.13

Here is my hibernate.cfg.xml file:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
  "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="show_sql">true</property>
    <property name="hbm2ddl.auto">update</property>

    <property name="connection.provider_class">org.hibernate.hikaricp.internal.HikariCPConnectionProvider</property>
    <property name="hikari.maximumPoolSize">10</property>
    <property name="hikari.dataSource.cachePrepStmts">true</property>
    <property name="hikari.dataSource.prepStmtCacheSize">250</property>
    <property name="hikari.dataSource.prepStmtCacheSqlLimit">2048</property>
    <property name="hikari.dataSource.useServerPrepStmts">true</property>
    <property name="hikari.dataSource.useLocalSessionState">true</property>
    <property name="hikari.dataSource.useLocalTransactionState">true</property>
    <property name="hikari.dataSource.rewriteBatchedStatements">true</property>
    <property name="hikari.dataSource.cacheResultSetMetadata">true</property>
    <property name="hikari.dataSource.cacheServerConfiguration">true</property>
    <property name="hikari.dataSource.elideSetAutoCommits">true</property>
    <property name="hikari.dataSource.maintainTimeStats">false</property>
    <property name="hikari.poolName">ServiceRegistry</property>
    <property name="hikari.registerMbeans">true</property>

  <!-- mappings ommited -->
  </session-factory>
</hibernate-configuration>

The driver class is not specified, it is left to Hibernate to autoconfigure it based on the provided JDBC url (so it’s easier to switch to postgresql from mysql for example).

I have a singleton class named DatabaseManager where I obtain a session factory like so:

Configuration configuration = new Configuration().configure("hibernate.cfg.xml")
                                                         .setProperty("hibernate.connection.url", dbAddress)
                                                         .setProperty("hibernate.connection.username", dbUser)
                                                         .setProperty("hibernate.connection.password", dbPassword);
        sessionFactory = configuration.buildSessionFactory();

dbAddress, dbUser and dbPassword is read from a property file. I have MySQL server 5.7 running on port 3306, and MySQL server 8 on port 3316. When the JDBC url points to the older server, everything works fine, as it did, before updating my dependencies. When trying to connect to the newer version of MySQL server (db_address=jdbc:mysql://127.0.0.1:3316/name_of_the_db), I get the following stacktrace during startup:

Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
	at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:275)
	at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237)
	at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
	at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152)
	at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.java:286)
	at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:243)
	at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
	at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:179)
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:119)
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:84)
	at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:474)
	at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:85)
	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:689)
	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:724)
	at eu.arrowhead.common.DatabaseManager.<clinit>(DatabaseManager.java:59)
	... 3 more
Caused by: org.hibernate.HibernateException: com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: Access denied for user 'root'@'localhost' (using password: NO)
	at org.hibernate.hikaricp.internal.HikariCPConnectionProvider.configure(HikariCPConnectionProvider.java:63)
	at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:100)
	at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:246)
	at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
	at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.buildJdbcConnectionAccess(JdbcEnvironmentInitiator.java:145)
	at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:66)
	at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35)
	at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:94)
	at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
	... 17 more
Caused by: com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: Access denied for user 'root'@'localhost' (using password: NO)
	at com.zaxxer.hikari.pool.HikariPool.throwPoolInitializationException(HikariPool.java:576)
	at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:562)
	at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:115)
	at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:81)
	at org.hibernate.hikaricp.internal.HikariCPConnectionProvider.configure(HikariCPConnectionProvider.java:59)
	... 25 more
Caused by: java.sql.SQLInvalidAuthorizationSpecException: Access denied for user 'root'@'localhost' (using password: NO)
	at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.get(ExceptionMapper.java:232)
	at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.getException(ExceptionMapper.java:165)
	at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connectWithoutProxy(AbstractConnectProtocol.java:1199)
	at org.mariadb.jdbc.internal.util.Utils.retrieveProxy(Utils.java:560)
	at org.mariadb.jdbc.MariaDbConnection.newConnection(MariaDbConnection.java:174)
	at org.mariadb.jdbc.Driver.connect(Driver.java:92)
	at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:136)
	at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:369)
	at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:198)
	at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:467)
	at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:541)
	... 28 more
Caused by: java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: NO)
Current charset is UTF-8. If password has been set using other charset, consider using option 'passwordCharacterEncoding'
	at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.authentication(AbstractConnectProtocol.java:931)
	at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.handleConnectionPhases(AbstractConnectProtocol.java:850)
	at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connect(AbstractConnectProtocol.java:507)
	at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connectWithoutProxy(AbstractConnectProtocol.java:1195)
	... 36 more

I omitted my own exception at the top, line 59 of DatabaseManager is sessionFactory = configuration.buildSessionFactory();

By the way I also get this warning right at the start: Loading class com.mysql.jdbc.Driver'. This is deprecated. The new driver class iscom.mysql.cj.jdbc.Driver’. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
This is there since the dependency updates, no matter which server I’m trying to connect to.

What can be the problem? I also tried directly specifying the username and password for HikariCP, but that did not help, as expected based on the Hibernate user guide. Is MySQL 8 supported by Hibernate?


#2

Turns out if I specify the following property:

<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>

Then the startup will be successful, although the mentioned warning is still showed.


#3

Why are you using the MariaDB Driver to connect to MySQL?

org.mariadb.jdbc.internal

The issue is because the config did not pass the URL and Password.

Caused by: java.sql.SQLException: Access denied for user ‘root’@‘localhost’ (using password: NO)

Now, why do you even mix properties from the hibernate configuration file and the one provided to the deprecated Configuration?

.setProperty("hibernate.connection.url", dbAddress)
.setProperty("hibernate.connection.username", dbUser)
.setProperty("hibernate.connection.password", dbPassword);

#4

I have an idea about how the MariaDB driver got there, I will check that tomorrow.

I’m using the Configuration class to programatically provide the jdbc url, db username and password. I do not want to hardcode those into the hibernate config file, because

  1. This is in an open source project
  2. There are many different modules with their own config file, which could connect to different databases.

I looked at the source code of Configuration, it doesn’t mention any deprecation for me at the configure(String) or setProperty(String, String) methods.
What’s the preferred alternative to the Configuration class? Or can you tell from this why wasn’t the password passed to the session? (in my test case, the dbUser was actually root, but it might have just defaulted to that value).


#5

You can do that with Maven as well. Just pass the credentials from a System or Environment variable and have Maven substitute the ${db.password} token at build time.

I looked at the source code of Configuration, it doesn’t mention any deprecation for me at the configure(String) or setProperty(String, String) methods.

It’s not the code that’s deprecated. It’s the entire Configuration-based bootstrapping that’s deprecated. You should read the User Guide for more details about the new native bootstrap mechanism.

Or can you tell from this why wasn’t the password passed to the session? (in my test case, the dbUser was actually root, but it might have just defaulted to that value).

You need to debug it and see why it didn’t get through.