Needs clarity on hibernate second level cache - java

I need some clarification with the Hibernate second level cache.
How does the hibernate second level cache works?
Does it loads all the data from the tables for which there is #Cacheable annotation (with respect to hibernate annotation) in the entity classes on server start up in the Java EE environment?
Will the cache gets sync up when there is an update on those tables and how?
Last one is there any ways for my DAO code to get notified when there is an updated on some table which i am interested upon? (Looking for any listener which can intimate abt the updates of the tables).

How does the hibernate second level cache works?
When your entity is marked as cacheable and if you have configured the second level cache then hibernate will cache the entity to the second level cache after the first read.
Hibernate provides the flexibility to plugin any cache implementation that follows hibernates specification. Refer Hibernate Manual for more details on second level cache and configurations options.
Does it loads all the data from the tables for which there is #Cacheable annotation (with respect to hibernate annotation) in the entity classes on server start up in the Java EE environment?
I don't think there is any configuration for achieving this. Indirectly you can achieve this by reading the entire table in startup, this can adversely affect the system startup time. (i don't prefer this). If the entity is modified externally, then hibernate can't sync it and you will end up getting stale data.
Will the cache gets sync up when there is an update on those tables and how?
The cache won't get updated instantly after the table update. The subsequent call to fetch the updated record will go the database, hibernate achieves this internally by using session timestamps.
Last one is there any ways for my DAO code to get notified when there is an updated on some table which i am interested upon? (Looking for any listener which can intimate abt the updates of the tables).
No, hibernate doesn't support this.

That's a too broad question to be answered here.
No. It populates the cache lazily. Each time you get a cachable entity from the database, using the hibernate API or a query, this entity is stored in the cache. Later, when session.get() is called with an ID of an entity that is in the cache, no database query is necessary.
If the update is made through Hibernate, then the cache is updated. If it's done using an external application, or a SQL query, or even a bulk update HQL query, then the cache is unaware of the update. That's why you need to be careful about which entities you make cachable, which time-to-live you choose, etc. Sometimes, returning stale values is not problematic, and sometimes it is unacceptable.
No.

Related

Preloading JPA/Hibernate entities to an in-memory cache

at work we are using Java EE (WildFly) with an ever increasing workload. Persistence layer uses EJBs with JPA and Hibernate. One table (main data table) gets like 99% of the traffic and database size, while there are a bunch of others that are used to described the data.
It works, but sometimes it slows down, due to many description entities that have to be loaded while saving the data table entities. We can't seem to get the 2nd level Hibernate cache going, so we are currently looking into in-memory caching.
The basic idea is just a simple HashMap for each of the description entities I mentioned above. We are talking about 10 tables with 50k records total, so it wouldn't impact the database badly.
Load all of them at startup, put them in the HashMap, link them with other cached entities (Some description entities have relations between themselves). When one of the entities is updated, replace it in cache with an updated version. While the reside in the cache, they are evicted and should behave like normal POJOs.
We've also looked into some real caching solutions like JCache, Caffeine, etc, but aren't sure if we really need the features they offer.
Does any of this make sense? Or is it a stupid approach to the problem?
Second level caching of Hibernate will take care of all of that. It will transparently put objects into the cache and evict them if some transaction (of that application) changes data. 2nd level caching refers to caching of entity object in a cache. There also is a query cache, which makes use of the second level cache. Note that the query cache needs to be enabled on a per query basis though with org.hibernate.query.Query#setCacheable

How check when cache is empty and I should load it

I use technologies like spring boot, jpa and java 8. I have a question, how can I check if the cache is empty and I should send a query to the database to reload it (how to check that I need to reload the cache)?
As your question is not clear about regarding what type of cache you are using ??
JPA uses the first level of caching is the persistence context.
The Entity Manager guarantees that within a single Persistence Context, for any particular database row, there will be only one object instance. However the same entity could be managed in another User's transaction, so you should use either optimistic or pessimistic locking.
If you mean 2nd level cache ,This level of cache came due to performance reasons.this 2nd level cache sits between Entity Manager and the database. Persistence context shares the cache, making the second level cache available throughout the application. Database traffic is reduced considerably because entities are loaded in to the shared cache and made available from there. So actually laying you dont need to worry about reloading of data from database if cache miss happens.
Now if you are implementing your own logic to implement the cache , then you need to do more research on how actually caching works and different algorithms for caching like LRU,MRU etc. (which I would personally not recommend as you can use existing available providers like ehcache, redis,hazelcast just few names for 2nd level caching )

How to use hibernate cache in different app with the same database?

I have 2 applications, which using the same database. The first app can write and read from database. The second app only read from database.
I include second-level hibernate cache with read-write strategy. And now, when I change data from the first app, I don't see this changes at the second app.
How to resolve this issue?
Disclaimer: I am not an hibernate expert, maybe somebody else can give a more cripsy answer...
This is the same question on SO:
Hibernate 2nd level cache invalidation when another process modifies the database However it seems fairly outdated.
You need to look for a distributed or replicated cache and follow the documentation of the respective product. Examples:
Using Infinispan as JPA second level cache provider
Using EHCache and hibernate
Some blog articles about it:
http://codespot.net/2014/02/03/hibernate-caching-strategies
http://vladmihalcea.com/how-does-hibernate-store-second-level-cache-entries
If one application directly writes to the database you need to properly invalidate the second level caches by yourself.

Update a single object across multiple process in java

A couple of Relational DB tables are managed by a single object cache that resides in a process. When the cache is committed the tables are updated. The DB relational tables are updated by regular SQL queries and not anything more fancier like hibernate.
Eventually, other processes got into the business of modifying this object without communicating with one another i.e, Each process would initialize this object (read from DB) and update it( commit to DB), & other process would not know about it holding on to a stale cache.
I have to fix this workflow. I have thought of couple of methods.
One is to make this object an mBean. So, the object would reside on one process and every process would eventually modify the object in that process by mBean method invocations.
However, this approach has a couple of problems.
1) Every object returned by this cache has be an mBean, which could make the method invocations quite chatty.
2) Also there is a requirement that every process should see a consistent data model(cache) of the DB, and it should merge its contents to the DB if possible. (like a transaction). If the DB was updated by some other process significantly, it is OK for the merge to fail.
What technologies in Java will help to solve this problem?
You should have a look at Terracotta. They have technology that makes multiple JVMs (can be on different servers) appear unified. If you update an object on one JVM, Terracotta will update the instance transparently on all JVMs in the cluster in a safe way.
If you wanted to keep the object model, you could use java object cache for centralized storage before committing. Or you could keep a shared lock using zookeeper.
But it sounds like you should really abandon the self-managed cache. Use hibernate or another JPA implementation, which you mentioned. JPA addresses the cache issues and maintains a L2 shared cache, so they've thought about this for you.
I agree with John - use a second level cache in hibernate with support for clustering. Much more straightforward way to manage data by using a simplified data access model and let Hibernate manage the details.
Terracotta Ehcache is one such cache, so is JBoss, Coherence, etc.
More info on Hibernate Second Level Cache can be had here and in the official Hibernate docs on Chapter 19. Improving Performance (note that the while the Hibernate docs do list second level cache providers, the list is woefully out of date, for example who uses Swarm Cache? The last release of that was in 2003)

Hibernate transaction problem

When I execute some queries inside Hibernate transaction -> the data successfully updated in my mysql, but in my application there are still old values. When i restart - it`s Ok. If i set autocommit mode - works fine, but i have to use transaction ;-). Any ideas?
Thanks in advance.
Manipulating the database directly with UPDATE doesn't affect the objects cached in the session. You should clear the session (Session.clear()). Something like:
session.flush()
session.clear()
query.executeUpdate()
Or even better, you can avoid the problem by not using update queries and manipulating the object state in memory:
myobj.setName(newValue)
session.saveOrUpdate(myobj)
In hibernate either you are using JPA API or Hibernate's native API any query that you run using below interface
Criteria (Hibernate Native API)
Query (Hibernate Native API)
EntityManager createQuery() (JPA)
The queries dont interact with the second level or first level cache . They directly hit the database .If your query is updating the entities currently in the persistence context , those entities will not reflect the changes.This is the default behavior.
In order to update your context to show the latest state of entity use the refresh() in Session or in EntityManager to reflect the latest entity state in persistence context.
Read the docs below for more info
http://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html#refresh-java.lang.Object-
https://docs.jboss.org/hibernate/orm/3.5/javadocs/org/hibernate/Session.html#refresh%28java.lang.Object%29
Otherwise as a convention always run your DML before loading any data in the persistence context.
Hope this helps :D

Categories

Resources