hibernate Cache
hibernate Cache
First Level Cache
https://www.journaldev.com/2969/hibernate-caching-first-level-cache
Associated with the Session, enabled by default .
Any object cached in a session will not be visible to other sessions and when the session is closed, all the cached objects will also be lost.
//Get employee with id=1 |
- Hibernate First Level cache is enabled by default, there are no configurations needed for this.
- Hibernate first level cache is session specific, that’s why when we are getting the same data in same session there is no query fired whereas in other session query is fired to load the data.
- Hibernate first level cache can have old values, as you can see above that I have put my program to sleep for 10 seconds and in that time I updated the value (name from Pankaj to PankajK) in database but it didn’t get reflected in the same session. But in other session, we got the updated value.
- We can use session
evict()
method to remove a single object from the hibernate first level cache. - We can use session
clear()
method to clear the cache i.e delete all the objects from the cache. - We can use session
contains()
method to check if an object is present in the hibernate cache or not, if the object is found in cache, it returns true or else it returns false. - Since hibernate cache all the objects into session first level cache, while running bulk queries or batch updates it’s necessary to clear the cache at certain intervals to avoid memory issues.
Second Level Cache
second-level cache is SessionFactory-scoped, meaning it is shared by all sessions created with the same session factory.
- If an instance is already present in the first-level cache, it is returned from there
- If an instance is not found in the first-level cache, and the corresponding instance state is cached in the second-level cache, then the data is fetched from there and an instance is assembled and returned
- Otherwise, the necessary data are loaded from the database and an instance is assembled and returned
Designed to be unaware of the actual cache provider used
we use Ehcache as a cache provider - ehcache
enable second-level cache
hibernate.cache.use_second_level_cache=true |
make 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.
|
ibernate will use a separate cache region to store state of instances for that class. The region name is the fully qualified class name. Foo instances are stored in a cache named com.baeldung.hibernate.cache.model.Foo in Ehcache.
Cache Concurrency Strategy
- *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
Expiration and eviction policies are not defined, the cache could grow indefinitely and eventually consume all of available memory.
eg: limit the maximum number of cached Foo instances to 1000:
<ehcache>
<cache name="com.baeldung.persistence.model.Foo" maxElementsInMemory="1000" />
</ehcache>
Cache Representation
Entities are not stored in second-level cache as Java instances, but rather in their disassembled (hydrated) state:
- Id (primary key) is not stored (it is stored as part of the cache key)
- Transient properties are not stored
- Collections are not stored (see below for more details)
- Non-association property values are stored in their original form
- Only id (foreign key) is stored for ToOne associations
Cache Invalidation for HQL DML-Style Queries and Native Queries
When it comes to DML-style HQL (insert, update and delete HQL statements), Hibernate is able to determine which entities are affected by such operations:
entityManager.createQuery("update Foo set … where …").executeUpdate(); |
In this case all Foo instances are evicted from L2 cache, while other cached content remains unchanged.
However, when it comes to native SQL DML statements, Hibernate cannot guess what is being updated, so it invalidates the entire second level cache:
session.createNativeQuery("update FOO set … where …").executeUpdate(); |
This is probably not what you want! The solution is to tell Hibernate which entities are affected by native DML statements, so that it can evict only entries related to Foo entities:
Query nativeQuery = entityManager.createNativeQuery("update FOO set ... where ..."); |
query Cache
Results of HQL queries can also be cached. To enable query cache, set the value of hibernate.cache.use_query_cache property to true:
hibernate.cache.use_query_cache=true
for each query you have to explicitly indicate that the query is cacheable (via an org.hibernate.cacheable query hint):
entityManager.createQuery("select f from Foo f") |