Inconsistent Behaivor of L2 cache between Hibernate 5 and 6

I am upgrading from Hibernate 5.6.15 to 6.1.7 and have noticed a
discrepancy on how the L2 cache works.
In 5.6.15, querying using an object parameter correctly reads from the cache,
where in 6.1.7 it does not.

For example:

@Test
@Order(20)
public void queryByObjectParameter_readFromDatabase() {
	resetSecondLevelCache();
	queryByObjectParameter();
}

@Test
@Order(21)
public void queryByObjectParameter_readFromL2Cache() {
	queryByObjectParameter();

	// This fails because querying by object results in a cache miss every time in Hibernate 6.1.7.
	// This succeeds in Hibernate 5.6.15.
	assertThat(getSecondLevelHitCount()).isEqualTo(1L); 
}

private void queryByObjectParameter() {
	Session session = entityManager.unwrap(Session.class);

	Query<Parent> queryParent = session.createQuery("from Parent p where p.name = 'John'", Parent.class);
	List<Parent> p = queryParent.getResultList();

	Query<Child> queryChildren = session.createQuery("from Child c where c.parent = ?1", Child.class);
	queryChildren.setParameter(1, p.get(0));
	queryChildren.setCacheable(true);
	List<Child> c = queryChildren.getResultList();
}

Support functions:

private void resetSecondLevelCache() {
	Session session = entityManager.unwrap(Session.class);
	session.getSessionFactory().getCache().evictQueryRegion("default-query-results-region");
	session.getSessionFactory().getStatistics().clear();
}

private long getSecondLevelHitCount() {
	Session session = entityManager.unwrap(Session.class);
	Statistics stats = session.getSessionFactory().getStatistics();
	CacheRegionStatistics regionStats = stats.getDomainDataRegionStatistics("default-query-results-region");
	return regionStats.getHitCount();
}

We notice that if we change the query to use an id parameter instead of an object
parameter, the query would correctly read from the L2 cache (as follows). However, even
though we found this workaround, it is still a big problem for our project because we have
a huge code base and it would be difficult for us to exhaustively find all queries and
ascertain we cover all suspect spots. This is clearly a regression. Whether we use an
object or an id as the parameter, L2 query cache should work for either of the two usage
patterns.

Query<Child> queryChildren = session.createQuery("from Child c where c.parent.id = ?1", Child.class);
queryChildren.setParameter(1, p.get(0).getId());

Here is the full runnable project.
HibernateTests is a test suite that demonstrates this.

Here is a branch of the project
set to Hibernate 5.6.15, showing all tests passing.

Hi there. Thanks for reporting the issue. Can you please create an issue in the issue tracker(https://hibernate.atlassian.net) and attach that test case?

1 Like

Thanks! I created [HHH-16281] - Hibernate JIRA