The getResultList
call in the findAll_test
method is hanging after many hundreds of requests.
public Session openSession() {
return this.sessionFactory.openSession(); // org.hibernate.SessionFactory
}
public <R> R with(Function<Session, R> function) throws SqlException {
try {
Session session = this.openSession();
R result = function.apply(session);
if (session.isDirty())
session.flush();
if (session.isOpen())
session.close();
return result;
} catch (Exception exception) {
throw new SqlException(exception); // SqlException extends RuntimeException
}
}
public final ConcurrentList<T> findAll_test() {
return this.with(session -> {
Class<T> tClass = this.getTClass();
// This is the database model/entity class,
// it's passed in the constructor,
// it's the class with @Entity, @Table annotations
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(tClass);
Root<T> rootEntry = criteriaQuery.from(tClass);
CriteriaQuery<T> all = criteriaQuery.select(rootEntry);
// Concurrent.newList is just a thread-safe list,
// it's not being used downstream for the purposes of this example,
return Concurrent.newList(
session.createQuery(all)
.setCacheable(true)
.getResultList() // This works ~1245 times, then hangs
);
});
}
If I run the above method approximately 1,245 times total, across tens of models/entities, it hangs inside getResultList
.
Here are my Hibernate/HikariCP/ehcache properties.
Properties properties = new Properties() {{
// Connection
put("hibernate.dialect", config.getDatabaseDriver().getDialectClass());
put("hibernate.connection.driver_class", config.getDatabaseDriver().getDriverClass());
put("hibernate.connection.url", config.getDatabaseDriver().getConnectionUrl(config.getDatabaseHost(), config.getDatabasePort(), config.getDatabaseSchema()));
put("hibernate.connection.username", config.getDatabaseUser());
put("hibernate.connection.password", config.getDatabasePassword());
put("hibernate.connection.provider_class", "org.hibernate.hikaricp.internal.HikariCPConnectionProvider");
// SQL
put("hibernate.generate_statistics", config.isDatabaseDebugMode());
put("hibernate.show_sql", false);
put("hibernate.format_sql", false); // Log Spam
put("hibernate.use_sql_comments", true);
put("hibernate.order_inserts", true);
put("hibernate.order_updates", true);
put("hibernate.globally_quoted_identifiers", true);
// Prepared Statements
put("hikari.cachePrepStmts", true);
put("hikari.prepStmtCacheSize", 256);
put("hikari.prepStmtCacheSqlLimit", 2048);
put("hikari.useServerPrepStmts", true);
// Caching
put("hibernate.cache.use_second_level_cache", true);
put("hibernate.cache.use_query_cache", true);
put("hibernate.cache.region.factory_class", "org.hibernate.cache.jcache.JCacheRegionFactory");
put("hibernate.cache.provider_class", "org.ehcache.jsr107.EhcacheCachingProvider");
put("hibernate.cache.use_structured_entries", config.isDatabaseDebugMode());
}};
Here are two scenarios that "hide" the problem:
- If I remove
hibernate.cache.use_query_cache
(or set it to false), my application gets significantly slower, but it no longer encounters this problem. - If I change the expiry policy from a duration of one minute, to five minutes then it also prolongs how long I can run the above method by a factor of 5.
The problem lies with the hibernate query cache. When disabled, this problem does not occur. There appears to be a deadlock when querying the way I do (for all entities) as the cache expires.
Dependencies:
- Hibernate and HikariCP 5.5.7.Final
- ehcache 3.9.9
- mariadb-java-client 2.7.4
- MariaDB server 10.3.28