Native query and caching mechanism of Hibernate

12,207

Using SQLQuery, Hibernate couldn't know what cache regions you might affect, but luckily you can explicitly instruct it:

SQLQuery sqlQuery = session.createSQLQuery(
    "UPDATE CUSTOMER SET ... WHERE ..."); 
sqlQuery.addSynchronizedEntityClass(Person.class); int
int updateCount = sqlQuery.executeUpdate();

This way it knows what query caches to invalidate, otherwise it may discard everything:

private static class EntityCleanup {
    private final EntityRegionAccessStrategy cacheAccess;
    private final SoftLock cacheLock;

    private EntityCleanup(EntityRegionAccessStrategy cacheAccess) {
        this.cacheAccess = cacheAccess;
        this.cacheLock = cacheAccess.lockRegion();
        cacheAccess.removeAll();
    }

    private void release() {
        cacheAccess.unlockRegion( cacheLock );
    }
}

private static class CollectionCleanup {
    private final CollectionRegionAccessStrategy cacheAccess;
    private final SoftLock cacheLock;

    private CollectionCleanup(CollectionRegionAccessStrategy cacheAccess) {
        this.cacheAccess = cacheAccess;
        this.cacheLock = cacheAccess.lockRegion();
        cacheAccess.removeAll();
    }

    private void release() {
        cacheAccess.unlockRegion( cacheLock );
    }
}

private class NaturalIdCleanup {
    private final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy;
    private final SoftLock cacheLock;

    public NaturalIdCleanup(NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy) {
        this.naturalIdCacheAccessStrategy = naturalIdCacheAccessStrategy;
        this.cacheLock = naturalIdCacheAccessStrategy.lockRegion();
        naturalIdCacheAccessStrategy.removeAll();
    }

    private void release() {
        naturalIdCacheAccessStrategy.unlockRegion( cacheLock );
    }
}

So, as you can see the whole data from the Region is evicted.

This only affects the second-level cache. The first level cache (a.k.a. Session) is not cleared every time you run a native query, because that would detach all your current "attached entities", having unexpected consequences in entity state expectations. But before every query (HQL or native) the session is flushed so the DB and the session are in sync prior to executing the query, hence the 1st level cache is consistent before issuing a new select.

A whole region would get invalidated, not the whole second-level cache. An entity defines a cache region, so updating a specific entity table would only remove all the entities that belong to that particular table(s) that were affected by the native query.

But overriding the query-space definition associated with a native query is a way to customize Hibernate not to clear the cache region as it would do using the default implementation.

Share:
12,207
Beast
Author by

Beast

Updated on June 05, 2022

Comments

  • Beast
    Beast almost 2 years

    I have a question regarding Hibernate caching mechanism.I have read in the articles that native SQLquery execution in hibernate, invalidates all regions of cache because hibernate does not have any idea regarding which particular entity it is going to affect. Here all regions of cache means are we talking about various regions of the second level cache or both levels of cache(first level cache,second level cache) or only second level cache or only first level cache?

  • Beast
    Beast almost 10 years
    so it will invalidate only the second level cache ? But what about the first level cache then it won't invalidate it? As far I know this particluar function tells hibernate that which particular entity to invalidate rather than invalidating the whole cache.
  • Beast
    Beast almost 10 years
    Any body has answer to the above question? Can anybody clear my understanding?
  • Vlad Mihalcea
    Vlad Mihalcea almost 10 years
    Check my updated response, I hope it's clear enough.
  • Beast
    Beast almost 10 years
    @Thanks Vlad for your answer. Apology for late reply.
  • Beast
    Beast almost 10 years
    One question apology for eating your head, If i dont add the statement sqlQuery.addSynchronizedEntityClass(Person.class) still it would flush the first level cache ? Because hibernate does not have any idea regarding which particular table the native query has an effect?
  • Vlad Mihalcea
    Vlad Mihalcea almost 10 years
    The first level cache is flushed when you run any query. Hibernate has pending changes and any query must go to the DB, so the pending queries need to be flushed so the query returns consistent results.
  • Beast
    Beast almost 10 years
    That should depend upon you FlushMode If you FlushMode is Auto then it will automatically determines when should it flush the changes to the database. If your changes in the session or first level cache affect the query result then it would flush the changes. Is my understanding correct ?
  • Vlad Mihalcea
    Vlad Mihalcea almost 10 years
    "The Session is sometimes flushed before query execution in order to ensure that queries never return stale state." I think it's smart after-all.
  • Johnny
    Johnny over 8 years
    Vlad, does hibernate 4.x also clear 2nd level cache for every native query with update statement? Or this problem is actual only for hibernate 3.x?
  • Farhan Shirgill Ansari
    Farhan Shirgill Ansari over 6 years
    @VladMihalcea: I am using a native SQL query in JPA which loads some data from the db. The problem is when I update the data in one of columns from sql developer, and then try to load the same data, the changes are not reflected in the JPA side. If I restart the web applcn, then it works fine. We are using this databsource- com.mchange.v2.c3p0.ComboPooledDataSource. What could be the issue? Why is JPA Hibernate using the old data from the session rather than loading the latest data from db. Please suggest.
  • Vlad Mihalcea
    Vlad Mihalcea over 6 years
    Sounds like a question, rather than a comment to an answer.