We need to cache the results of a query; the query returns the whole table of a database. The problem is that the database is changed externally by other application; the Java application making the query is notified with the exact primary key of the row changed.
Is it possible to replace only the changed element from the query cache, not the whole list?
Is this the 1st level cache (from EntityManager) 2nd level Cache (from EntityManagerFactory) or a different cache?
If it is possible can this be done from JPA?
entityManager.refersh(entity);
or is this query cache the 2nd level JPA cache:
entityManagerFactory.getCache().evict(cls, primaryKey);
or only possible through Hibernate/EclipseLink API?
If is not possible, in order to achieve this, would calling entityManager.find() on all elements do it?
I haven't find anything useful neither in Hibernate documentation nor in EclipseLink documentation. Hibernate supports regions and refreshing only regions, but we need entity-level refresh granularity.
Later edit to clarify my findings.
Following the link posted by #Chris in the comment I have found out that what I wanted is actually supported by EclipseLink but only for Oracle Database (there is possible to implement own handler for other vendors; but the call from database is not standardized and differs from vendor to vendor). I have not found if Hibernate supports this or not.
Anyhow the query cache from EclipseLink had some very poor performance compared with Spring Cache (based on CocurrentMap) or with custom based cache so will remain with Spring Cache or Custom Cache over Spring Jdbc.
EntityManager.refresh() is what you want - it refreshes the entity from what is in the database. This should also update the entity in the shared cache if you are not in a transaction, otherwise you may need to use the entityManagerFactory.getCache().evict(cls, primaryKey); as well to clear the second level shared cache so it can be read into it as well later on.
Related
I have read that using hibernate's second level cache, it can improve applications performance by having less database hits for data / object retrieval.
However, how does hibernate ensure that second level cache is up to date with the data in database.
For, example:
Suppose the below class is entity and persisted into the DB.
#Entity
class User {
Id
private int id;
private String str;
}
Now, if we have enabled second level cache, I understand that if we open different sessions then each session will hit the second level cache for retrieving object value.
Now, if data in database gets changes (for e.g. for row with id=1) say by some independent process/ manually changing the values, and we try to access the value, how does hibernate detect that the cache is having latest value (for id = 1).
In general, how does hibernate ensure that data in second level cache is consistent with the db values.
Thanks for your help.
Hibernate manages the cache himself, so when you update some entity thru hibernate Session it will invalidate cache entry assocciated with this entity - so cache is always fresh.
If another process (or even second JVM running the same hibernate application) updates record in database, Hibernate on first JVM is unaware of this fact and has stale object in his cache.
However you can use any cache implementation (cache provider) you want. There are many production-ready cache providers that allow you to configure how long given entity will be stored in cache. For example you can configure your cache to invalide all entities after 30 seconds and so on.
If you use EhCache cache provider you can provide such configuration:
<cache name="com.my.company.Entity"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="7200"
timeToLiveSeconds="7200"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"/>
You can find more information abount L2 cache here:
http://www.tutorialspoint.com/hibernate/hibernate_caching.htm
however there is a lot of useful tutorials about this.
It doesn't.
If you change data in the database without using hibernate it won't know about it and your cache and the database get out of sync.
I have an Entity that right now it's stored on my database via Hibernate.
I'd like to remove it from database (as i'm not interested to relate it with other data, or to make some query) and i'd like to persist it on EHCache and dump all data on file ones a day.
I was wondering if i could do that without having an entity linked to database table.
What is your experience?
Unfortunately, it can't work the way you expect it to work.
Hibernate stores a dehydrated entity representation, so using the EHcache data directly will require you to implement a hydration/dehydration processing logic.
If you plan on porting to a non-standard data store, like using a persistent cache as a database, you need more control than Hibernate offers you.
I would try to replace Hibernate 2nd level cache with a service-layer caching implementation (e.g. Spring or even your custom caching abstraction layer). This way you control how the data is going to be serialized/deserialized.
But this is a significant amount of work, so I suggest you take a look on Redis.
I have a set of very heavy queries whose result I want to cache into an external Cache implementation (cache the whole object list not just ids like in Hibernate's 2nd level cache).
The issue is that due to the lazy loading of several collections in the root object, once the session that queried the results is done, the objects become de-attached and the next request that tries to use the object might throw a LazyLoading exception.
Environment: Spring 4, Hibernate 4.3, Ehcache.
Is there any way to be able to re-attach the object to a new session without having it modify the underlaying DB (like with merge and update)?
There is no way to reattach a detached entity to a session just to load a lazy-initialized collection.
In order to get an updated copy of a persistent object without overwriting the session / calling merge, it's necessary to call either EntityManager.find() or do a query.
This is because the main goal of the session is to keep the database and the objects in memory in sync. Due to this there is no API for attaching new state without persisting it, as this is not in line with the main functionality of the session.
The 2nd level cache, if configured together with the query cache can solve the problem of caching the entities, queries and their associations in a much better way than any custom solution.
Everything can get cached to the point that no query hits the database. The two caches really go together, check this blog post for further info.
I am using Spring + Ehcache for my caching layer. (via proxy)
I am wondering if you can cache both "findAll" result and "findById" result on the same cache and then CacheEvict the specific item and the "findAll" result (leaving the rest of the item untouched) and on the update and load it back to cache when "findById" again?
(or another way is to keep findAll and findById in 2 caches and when update CacheEvict allEntries for the findAll cache and the particular item on findById cache)
is this possible?
I will explain how hibernate with its second level and query cache work to give you a general idea. First of all Hibernate caches all single entities (e.g. retrieved by findById type of operations) in so-called second level cache.
If you retrieve all entities using findAll it puts primary keys of all entities in query cache (under one key) and all concrete entities in second level cache. When you call findAll again, it first retrieves all primary keys from query cache and then all entities from second level cache (or from database).
Invalidation is rather simple: INSERT and DELETE operations should invalidate the whole findAll query cache, while UPDATEs are transparent.
This should guide you how can you implement this in your solution. This is possible in Spring, but you might need to code a little bit, especially the part mapping from query cache to second level cache.
I have a scenario where I am displaying the data in the database which changes frequently (changed by outside application) on a webpage using Spring MVC, somewhat similar to a stock monitoring application. Currently i am using a daemon thread which fires on web container startup and queries the database every 45 secs and stores the data in the application wide hashmap object. And the web application reads the data from hashmap (instead of database) for displaying the data.
I have read about third party caching API's like Ehcache and OSCache. I have read the documentation on Ehcache and seems like I can use the Hibernate query caching technique instead of a daemon thread.
Now my query if I use hibernate and enable query caching and set timetoidle to 45 secs will the data in the cache is automatically refreshed to reflect latest data in the database or do i need force refresh (query the database again and repopulate the cache) the cache, also can you explain what a self populating cache is.
In the Ehcache docs a SelfPopulatingCacheis described as a:
A selfpopulating decorator for Ehcache that creates entries on demand.
That means when asking the SelfPopulatingCache for a value and that value is not in the cache, it will create this value for you. This blog article gives a lot of details and also code (inclusively auto-updating).
For me, it sounds that a Ehcache SelfPopulatingCache is what would fit your needs best. So I'd recommend to have a closer look at.
A Hibernate 2nd level cache would surely help to increase system performance, but not solve your problem, as I understand it. It's true when using Ehcache and setting timeToIdleSeconds the cache expires after that time, but it's not refreshed automatically.
Take a look at what Hibernate docs write about query cache:
The query cache does not cache the state of the actual entities in the cache; it caches only identifier values and results of value type. For this reason, the query cache should always be used in conjunction with the second-level cache for those entities expected to be cached as part of a query result cache (just as with collection caching).
Finally, OSCache is outdated.