Tuesday, May 15, 2018

How do you set hibernate second level cache with an example

Problem statement: What is hibernate second level cache?
Caching is facility provided by ORM frameworks which help users to get fast running web application, while help framework itself to reduce number of queries made to database in a single transaction. Hibernate also provide this caching functionality, in two layers.
  • Fist level cache: This is enabled by default and works in session scope. Read more about hibernate first level cache.
  • Second level cache: This is apart from first level cache which is available to be used globally in session factory scope.
Above statement means, second level cache is created in session factory scope and is available to be used in all sessions which are created using that particular session factory.
It also means that once session factory is closed, all cache associated with it die and cache manager also closed down.
Further, It also means that if you have two instances of session factory (normally no application does that), you will have two cache managers in your application and while accessing cache stored in physical store, you might get unpredictable results like cache-miss.
Region Factory:
We add the Ehcache region factory implementation to the classpath with the following Maven dependency:
   <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-ehcache</artifactId>
    <version>5.2.2.Final</version>
</dependency>

Enabling Second-Level Caching:

With the following two properties we tell Hibernate that L2 caching is enabled and we give it the name of the region factory class:
  1. hibernate.cache.use_second_level_cache=true
  2. hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
For example, in persistence.xml it would look like:
1
2
3
4
5
6
7
<properties>
    ...
    <property name="hibernate.cache.use_second_level_cache" value="true"/>
    <property name="hibernate.cache.region.factory_class"
      value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
    ...
</properties>
To disable second-level caching (for debugging purposes for example), just set hibernate.cache.use_second_level_cache property to false.

Making an Entity Cacheable

In order to make an entity eligible for second-level caching, we annotate it with Hibernate specific @org.hibernate.annotations.Cache annotation and specify a cache concurrency strategy.
Some developers consider that it is a good convention to add the standard @javax.persistence.Cacheable annotation as well (although not required by Hibernate), so an entity class implementation might look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Foo {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID")
    private long id;
    @Column(name = "NAME")
    private String name;
     
    // getters and setters
}
For each entity class, Hibernate will use a separate cache region to store state of instances for that class. The region name is the fully qualified class name.
Cache Concurrency Strategy:

org.hibernate.cache.CacheFactorypublic static final StringNONSTRICT_READ_WRITE"nonstrict-read-write"public static final StringREAD_ONLY"read-only"public static final StringREAD_WRITE"read-write"public static final StringTRANSACTIONAL"transactional"

Based on use cases, we are free to pick one of the following cache concurrency strategies:
  • READ_ONLY: Used only for entities that never change (exception is thrown if an attempt to update such an entity is made). It is very simple and performant. Very suitable for some static reference data that don’t change
  • NONSTRICT_READ_WRITE: Cache is updated after a transaction that changed the affected data has been committed. Thus, strong consistency is not guaranteed and there is a small time window in which stale data may be obtained from cache. This kind of strategy is suitable for use cases that can tolerate eventual consistency
  • READ_WRITE: This strategy guarantees strong consistency which it achieves by using ‘soft’ locks: When a cached entity is updated, a soft lock is stored in the cache for that entity as well, which is released after the transaction is committed. All concurrent transactions that access soft-locked entries will fetch the corresponding data directly from database
  • TRANSACTIONAL: Cache changes are done in distributed XA transactions. A change in a cached entity is either committed or rolled back in both database and cache in the same XA transaction
Cache Management:
If expiration and eviction policies are not defined, the cache could grow indefinitely and eventually consume all of available memory. In most cases, Hibernate leaves cache management duties like these to cache providers, as they are indeed specific to each cache implementation.
For example, we could define the following Ehcache configuration to limit the maximum number of cached Foo instances to 1000:
1
2
3
<ehcache>
    <cache name="org.baeldung.persistence.model.Foo" maxElementsInMemory="1000" />
</ehcache>

Query Cache:


Results of HQL queries can also be cached. This is useful if you frequently execute a query on entities that rarely change.
To enable query cache, set the value of hibernate.cache.use_query_cache property to true:
1
hibernate.cache.use_query_cache=true
Then, for each query you have to explicitly indicate that the query is cacheable (via an org.hibernate.cacheable query hint):
1
2
3
entityManager.createQuery("select f from Foo f")
  .setHint("org.hibernate.cacheable", true)
  .getResultList();

No comments:

Post a Comment

How to run standalone mock server on local laptop

 Please download the standalone wiremock server from Direct download section at the bottom of the page.  Download and installation Feel fre...