Why you need a query cache

Let's rewrite our example with getting employees in HQL:

Employee director1 = session.createQuery("from Employee where id = 4").uniqueResult();
Employee director2 = session.createQuery("from Employee where id = 4").uniqueResult();

assertTrue(director1 != director2);

The results of such queries are not stored by either the first or second level cache.

This is exactly where the query cache can be used . It is also disabled by default. To enable it, add the following line to the configuration file:

<property name="hibernate.cache.use_query_cache" value="true"/>

But this is only half the solution. We have enabled the query cache, but we also need to specify which query results we want to cache. This must be written in the Query:

Query query = session.createQuery("from Employee where id = 4");
query.setCacheable(true);
Employee director1 = query.uniqueResult();

The query cache is similar to a second level cache. But, unlike it, here the key to the cache data is not the object identifier, but the set of query parameters. And the data itself is the identifiers of the objects that match the query criteria. Thus, it is rational to use this cache with the second level cache.

Clearing the cache

One of the important tasks when working with a cache is to make sure that cached objects change and remove them from the cache (or update them). Hibernate does this very well. Sometimes it even seems that he is guided by the rule “clear the cache in any incomprehensible situation.”

Let's say you want to update user data via HQL:

Query query = session.createQuery("update Employee set name=’Alex’ where id = 4")
query. executeUpdate();

Hibernate cannot know exactly what has changed in the database, but it knows that you are changing an Employee object. Therefore, after executing this query, Hibernate will delete all objects of type Employee from its cache.

But NativeQuery works even more interesting:

Query nativeQuery = session.createNativeQuery("update employee set name=’Alex’ where id = 4")
nativeQuery.executeUpdate();

A native SQL query to the database has been executed. This means that something has changed in the database - the request was called in the executeUpdate() method . Therefore, in this case, Hibernate will play it safe and remove all objects of all types from its cache .

How do you like that? You call a harmless request, and Hibernate in response erases all the data from the cache! This is certainly better than if he kept objects that differ from the base, but that's it!

Therefore, the creators of Hibernate quickly figured out how to help Hibernate in this case. You can tell it which entity type to remove from the cache:

Query nativeQuery = session.createNativeQuery("update employee set name=’Alex’ where id = 4");
nativeQuery.unwrap(org.hibernate.SQLQuery.class).addSynchronizedEntityClass(Employee.class);
nativeQuery.executeUpdate();
Remark . Native select queries don't flush the cache , only insert, update, delete, procedure calls, etc.

Manual cache clearing

For certain reasons, you may want to delete an object from the cache yourself. This can be done in different ways.

Note . Objects in the cache are stored in groups called regions . By default, the region name is the same as the class name. Therefore, if you have objects of type com.codegym.Employee , then all of them will be stored in a group (region) with the name “ com.codegym.employee ”.

If you want to access the cache and do something with it, you can do it with the SessionFactory object and the getCache() method :

session.getSessionFactory().getCache().evictQueryRegion("com.codegym.employee”);

If you want to delete data from all groups (regions), then you need to run the following query:

session.getSessionFactory().getCache().evictAllRegions();

To remove one object from the cache, you need to pass its name (type) and id. You can do this in two ways:

session.getSessionFactory().getCache().evictEntityData("Employee, 4);

session.getSessionFactory().getCache().evictEntityData(com.codegym.Employee.class, 4);

You can also check if a particular object is in the cache:

session.getSessionFactory().getCache().containsEntity("Employee, 4);
session.getSessionFactory().getCache().containsEntity(com.codegym.Employee.class, 4);
undefined
1
Task
Module 4. Working with databases, level 14, lesson 6
Locked
Query cache
task1406