Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When and how to use hibernate second level cache?

I have trouble understanding when hibernate hits the second level cache and when does it invalidate the cache.

This is what I currently understand:

  • Second level cache stores entities between sessions, scope is the SessionFactory
  • You have to tell which entities to cache, no entity will get cached by default
  • Query cache stores results of queries in the cache.

What I don't understand is

  • When does hibernate hit this cache?
  • Let's say I've set up the second level cache but not the query caching. I want to cache my customers, there's 50000 of them. In what ways can I retrieve the customers from the cache?
  • I assume I can get them by id from cache. That would be easy but also not worthy of caching. But what if I want to do some calculation with all my customers. Let's say I want to show a list of the customers then how would I access them?
  • How would I get all my customers if query caching is disabled?
  • What would happen if someone updated one of the customers?
    • Would that customer get invalidated in the cache or would all customers get invalidated?

Or am I thinking caching totally wrong? What would be more appropriate uses of second level cache in that case? The hibernate documentation is not at all clear how the cache works in reality. There are only instructions on how to get it set up.

Update: So I've come to understand that second level cache(without query cache) would be good for loading data by id's. For example I have user object that I want to check for permissions in every request in a web application. Would this be a good case to reduce database access by caching the user in the second level cache? Like I would store the user id in the session or wherever and when I need to check for permissions I would load the user by it's id and check permissions.

like image 665
palto Avatar asked Aug 14 '11 18:08

palto


People also ask

When should I use Hibernate cache?

Hibernate caching acts as a layer between the actual database and your application. It reduces the time taken to obtain the required data — as it fetches from memory instead of directly hitting the database. It is very useful when you need to fetch the same kind of data multiple times.

How Hibernate 2nd Level cache works?

This cache only works at a session level, meaning each session object caches data independently, so there is no sharing of cached data across sessions, and the cached data is deleted when the session closes. This makes the cache only useful for repeated queries in the same session.

What is use of second level cache?

A second-level cache is a local store of entity data managed by the persistence provider to improve application performance. A second-level cache helps improve performance by avoiding expensive database calls, keeping the entity data local to the application.

What is the disadvantage of 2nd level caching?

Performance degrade. Yes, having caching do NOT necessary to give you better performance. Hibernate needs to do extra work to store and update the cache. If the entities cached are changed frequently and you are not querying them frequently, enabling the cache is just adding unnecessary extra burden.


2 Answers

First of all, let's talk about process level cache (or 2nd level cache as they call it in Hibernate). To make it work, you should

  1. configure cache provider
  2. tell hibernate what entities to cache (right in hbm.xml file if you use this kind of mapping).

You tell to the cache provider how many objects it should store and when/why they should be invalidated. So let's say you have a Book and an Author entities, each time you're getting them from the DB, only those that are not in cache will be selected from actually DB. This increases performance significantly. It's useful when:

  • You write to the database only via Hibernate (because it needs a way to know when to change or invalidate entities in the cache)
  • You read objects often
  • You have a single node, and you don't have replication. Otherwise you'll need to replicate the cache itself (use distributed caches like JGroups) which adds more complexity, and it doesn't scale as good as share-nothing apps.

So when does cache work?

  • When you session.get() or session.load() the object that was previously selected and resides in cache. Cache is a storage where ID is the key and the properties are the values. So only when there is a possibility to search by ID you could eliminate hitting the DB.
  • When your associations are lazy-loaded (or eager-loaded with selects instead of joins)

But it doesn't work when:

  • If you don't select by ID. Again - 2nd level cache stores a map of entities' IDs to other properties (it doesn't actually store objects, but the data itself), so if your lookup looks like this: from Authors where name = :name, then you don't hit cache.
  • When you use HQL (even if you use where id = ?).
  • If in your mapping you set fetch="join", this means that to load associations joins will be used everywhere instead of separate select statements. Process level cache works on children objects only if fetch="select" is used.
  • Even if you have fetch="select" but then in HQL you use joins to select associations - those joins will be issued right away and they will overwrite whatever you specified in hbm.xml or annotations.

Now, about Query Cache. You should note that it's not a separate cache, it's an addition to the process level cache. Let's say you have a Country entity. It's static, so you know that each time there will be the same result set when you say from Country. This is a perfect candidate for query cache, it will store a list of IDs in itself and when you next time select all countries, it will return this list to the process level cache and the latter, in turn, will return objects for each ID as these objects are stored already in the 2nd level cache. Query cache is invalidated each time anything related to the entity changes. So let's say you configured from Authors to be placed into a Query Cache. It won't be effective as Author changes often. So you should use Query Cache only for more or less static data.

like image 152
Stanislav Bashkyrtsev Avatar answered Oct 10 '22 00:10

Stanislav Bashkyrtsev


  • the 2nd level cache is a key-value store. It only works if you get your entities by id
  • the 2nd level cache is invalidated / updated per entity when an entity is updated/deleted via hibernate. It is not invalidated if the database is updated in a different way.
  • for queries (e.g. list of customers) use the query cache.

In reality it is useful to have a key-value distributed cache - that's what memcached is, and it powers facebook, twitter and many more. But if you don't have lookups by id, then it won't be very useful.

like image 45
Bozho Avatar answered Oct 10 '22 02:10

Bozho