-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: Query cache for findByNaturalId
PostPosted: Thu Jan 17, 2013 4:03 am 
Newbie

Joined: Wed Jan 16, 2013 12:01 pm
Posts: 2
Hello,

I'm running the following setup:
  • Hibernate 4.1.1.Final
  • Second Level Cache and Query Cache enabled
  • A currency entity mapped as follows:
    Code:
    @Entity
    @Immutable
    @Table( name = "CURRENCY" )
    @Cacheable
    @Cache( usage = READ_ONLY )
    @NaturalIdCache( region = CacheRegions.findByNaturalId )
    public class Currency extends BaseEntity implements Asset {
        ...
        @NaturalId
        private String isoCode;
        ...
    }
  • A CurrencyRepository that provides a findByIsoCode(String isoCode) method.

What is the best way to implement this simple finder method which is in fact a findByNaturalId?

Variation 1
My 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 2
So 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 3
So 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


Top
 Profile  
 
 Post subject: Re: Query cache for findByNaturalId
PostPosted: Fri Jan 18, 2013 3:30 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Hi Harmen,

Variation 2 ist the most compact and also the right approach:
The @NaturalId annotation provides a first-level caching (within persistent context),
whilst the @NaturalIdCache annotation assures caching on second level (aka shared cache).
I use Variation 2 and it works great for me.

Quote:
Why did the first and second variation not use the query cache?


Because there is another 2nd level cache for NaturalId's, the internal architecture there is different from the query cache.
For example your natural id 2nd level cache entries shall not be invalidated whenever there are modifications to the currency table,
as it indeed occurs with query caching as you correctly pointed out.
The reasons why your hibernate is continuously firing sql selects for the same isoCode against the database might be one of following:
Hibernate 4.1.1 has still some bug's regarding NaturalId Caching, therefore
I strongly suggest to switch to Hibernate 4.1.8 (or Hibernate 4.1.10 which will be released in next days).

Another reason for the continuously firing sql selects might be the configuration of your cache region.
Can it be that you configured it to small or that the cached entries are expiring to fast?
Which 2nd-level cache implementation are you using? (I use Ehcache)


Top
 Profile  
 
 Post subject: Re: Query cache for findByNaturalId
PostPosted: Mon Jan 21, 2013 11:00 am 
Newbie

Joined: Wed Jan 16, 2013 12:01 pm
Posts: 2
Hello and thanks a lot for your quick reply.

I switched my hibernate dependencies to 4.1.8.FINAL but still see hibernate constantly firing sql selects for the same isoCode when I switch to variation 2.

I don't think that the cache configuration is the problem because I use the same cache configuration for variation 3 (which works fine) and variation 2 (which doesn't seem to work).

I use hibernate-ehcache 4.1.8.FINAL as second level cache.


Top
 Profile  
 
 Post subject: Re: Query cache for findByNaturalId
PostPosted: Thu Aug 01, 2013 3:56 pm 
Pro
Pro

Joined: Wed Nov 05, 2003 7:22 pm
Posts: 211
So, how would this relate to @ManyToOne.
Let's say we have class Country and we want to make sure that currency is always retrieved from cache.

Code:
public class Country{
   @ManyToOne
   @JoinColumn(name="FK_CurrencyId")
   public Currency getCurrency(){...}
}


Would you annotate this method with
* @Cache(region = CacheRegions.findByNaturalId)
* No annotations, Hibernate is smart enough
* [...]

Is Hibernate "smart enough" to figure out that the id stored at FK_CurrencyId relates to the naturalId isoCode:"EUR"?

Also, where do you put the region, on the @Cache annotation or @NaturalIdCache notation?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.