Hello,
I'm running the following setup:
What is the best way to implement this simple finder method which is in fact a findByNaturalId?
Variation 1My first version used
Restrictions.naturalId():
Code:
final Criteria criteria = hibernateSession().createCriteria( Currency.class );
criteria.add( naturalId().set( "isoCode", isoCode ) );
criteria.setCacheable( true );
criteria.setCacheRegion( CacheRegions.findByNaturalId );
return (Currency) criteria.uniqueResult();
Although I clearly specify the criteria to be cacheable, I continuously see that hibernate is firing sql selects for the same isoCode against the database (meaning: no query cache is used to quickly map naturalIds to ids).
I also see warnings in the log that I should use
Session.byNaturalId() instead of
Restrictions.naturalId().
Variation 2So I change it to the second variation that uses
Session.bySimpleNaturalId(). Since
SimpleNaturalIdLoadAccess does not provide any methods like
setCacheable() and
setCacheRegion(), I could only hope that caching is by default enabled for those queries and that the annotation
@NaturalIdCache( region = CacheRegions.findByNaturalId ) ensures that the correct cache region is used:
Code:
final SimpleNaturalIdLoadAccess query = hibernateSession().bySimpleNaturalId( Currency.class );
return (Currency) query.load( isoCode );
Unfortunately, I also see that hibernate is continuously firing sql selects for the same isoCode against the database (meaning: no query cache is used to quickly map naturalIds to ids).
Variation 3So I changed to the last variation which uses a normal hibernate query (i.e. hibernate won't be informed that I'm doing a findByNaturalId). In fact I'm using QueryDSL here, but that won't make a difference, you'll get the point:
Code:
final HibernateQuery query = new HibernateQuery( hibernateSession() ).from( currency )
.where( currency.isoCode.eq( isoCode ) );
query.setCacheable( true );
query.setCacheRegion( findByNaturalId );
return query.uniqueResult( currency );
Now finally the query cache is used. I do no longer see hibernate firing sql selects to find out the id of the currency. Instead hibernate now uses the second level cache to find out the currency id and then uses the second level cache to get the currency with that id.
Why did the first and second variation not use the query cache?
Especially for the first variation that uses
Restrictions I really don't understand why the query cache isn't used.
For the second variation, how can one ensure query caching for
SimpleNaturalIdLoadAccess?
What is the annotation
@NaturalIdCache really used for (The documentation doesn't reveal much on that point)?
Right now I'm happy with my last variation because I won't have modifications on the currency table.
But what to do when the entity gets modified? Afaik, the query cache from the last variation will be invalidated whenever there are modifications to the currency table.
Thanks a lot for your help
Harmen