Spring + Ehcache : How to cache find all result - java

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.

Related

is it necessary for query caching region to be same as entity caching region

in my project i have enabled hibernate query caching (using ehcache) and 2nd level entity caching for some of the entities . also in the documentation it is mentioned that query caching does not store the complete entity object and only stores the entity identity. So we should enable 2nd level entity caching as well in order to achieve better performance.
I was wondering if query caching region and entity caching region should be same ? or is it ok for them to be different and still entity will be returned from 2nd level cache if its a result of query cached in query cache?
Another question I have is, is it ok to configure different 2nd level cache regions for different entities based on business categorization ?
The query cache uses its own region, just like entities should use individual regions.
This allows you to configure each region based on the cache access patterns.
It does not matter whether the query cache is in one region while the entities being cached are in different regions. If will work just fine.

How hibernate ensures second level cache is updated with latest data in database

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.

Replace single entity in query cache from JPA/Hibernate/EclipseLink?

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.

Caching de-attached Hibernate entities in external Cache

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.

Hibernate Second Level Cache In Case of Soft Delete

Read operations are very high as compare to insert/update/delete for master data module. We are using JDBC for read,write and update operations till now. We are doing soft delete (Marking IS_DELETED column to 'Y') on delete operation. All write/update methods are synchronized to handle the concurreny. We are using oracle and have no plan to support multiple databases.
Now, We are planning to cache the data and we also have plans to go for clustering.
The easiest option we have is to change the insert/update/delete methods and use something like ehcache to manage the cache as per our requirement and handle concurrency in the clustered environment by using version column in the table and remove synchronized keyword.
Other option that people around me are suggesting (Infact asking me to do) is to move to the hibernate (I don't know much about hibernate) which will take care of caching and concurrency automatically.
Here are my doubts:
1) Is it worth to change the complete DAO code given we have around 200 tables to mangage the master data ?.
2) Would hibernate second level cache help in this case given we need to filter the cached data again to discard deleted rows or there is a mechanism in hibernate (or any other way) by which we can perform update operation in database but delete operation in the cached data ?
3) We have exposed the data transfer objects to other modules having all the fields of the table with primary key stored in the separate PK Objects (Having Primary key fields in a separate object) and we don't have reference DO in it (Composite DO are not there). Given, We can't afford to change the exposed methods and DO structure - so do we have to pack the hibernate cached entities data in our DO again ? Or we can reuse the old DO structure as hibernate entity (As Per my understaindg PK column should be there directly in the hibenate entity rather than being in some composite object). I mentioned composite DO because we also have dependent dropdown requirement which could have been used with hibernate lazy loading for the child objects if we would have composite DO at the first place. Argument against is to provide new methods which would use cached data and depricate the old methods. Other modules would slowly migrate as per their need on caching but we will have maintaince issues as we have to maintain both methods in case of the db changes. Also, 1 and 2 doubts are still there.
I am sure that hibernate is not the way to go for us at this stage and I have to convince people around me but I want to know your views on long term advantages of moving to hibernate other than automatic management of second level cache, concurrency handling (Can we done by small code change at common place) and db indepedency (We are not interested in) on the cost of changing the complete code.
If you plan to migrate to hibernate you should take in account
1) You'll need to map all your structure to POJO's (if you have not already)
2) Rewrite all DAO's to use hibernate (bare in mind, that hibernate QL/criteria API has certain limitations
3) Be ready to fight lazy initialization problems and so on...
Personaly i don't thinks it's worth migrating to hibernate with working model unless it's extremly painfull to maintain current model
Concerning your 2 and 3 questions
2) Second level cache holds only loaded instances, accessed by primary key. i.e. if you say hibernateSession.load(User, 10) - it will lookup User object in second level cache using id=10. If i understand clearly that's not the case. Most of the time you want to load your data using more complex query - in that case you will need StandarQueryCache, which will map your query string to a list of loaded IDs which in turn will be retrieved from second-level cache. But if you have a lot of queries with a low similarity - both StandartQueryCache and second level cache will be total useless (take a look http://darren.oldag.net/2008/11/hibernate-query-cache-dirty-little_04.html)
3)You can use components and such, but im not sure about your DTO structure.
Hope that helps

Categories