为什么需要查询缓存

让我们用 HQL 中的员工重写我们的例子:

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

assertTrue(director1 != director2);

此类查询的结果不存储在一级或二级缓存中。

这正是可以使用查询缓存的地方。它也是默认禁用的。要启用它,请将以下行添加到配置文件中:

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

但这只是解决方案的一半。我们启用了查询缓存,但我们还需要指定要缓存哪些查询结果。这必须写在查询中:

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

查询缓存类似于二级缓存。但是,与它不同的是,这里缓存数据的关键不是对象标识符,而是查询参数集。而数据本身就是符合查询条件的对象的标识。因此,将此缓存与二级缓存一起使用是合理的。

清除缓存

使用缓存时的一项重要任务是确保缓存的对象发生更改并将它们从缓存中删除(或更新它们)。Hibernate 在这方面做得很好。有时甚至看起来他被“在任何无法理解的情况下清除缓存”的规则所引导。

假设您想通过 HQL 更新用户数据:

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

Hibernate 无法确切知道数据库中发生了什么变化,但它知道您正在更改 Employee 对象。因此,执行此查询后,Hibernate 将从其缓存中删除所有 Employee 类型的对象。

但 NativeQuery 的工作方式更有趣:

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

已执行对数据库的本机 SQL 查询。这意味着数据库中发生了一些变化——在executeUpdate()方法中调用了请求。因此,在这种情况下,Hibernate 会谨慎行事,并从其缓存中删除所有类型所有对象

你觉得如何?你调用一个无害的请求,Hibernate 作为响应从缓存中删除所有数据!这肯定比他保留与底座不同的物体要好,但仅此而已!

因此,Hibernate 的创建者很快想出了如何在这种情况下帮助 Hibernate。您可以告诉它要从缓存中删除哪种实体类型:

Query nativeQuery = session.createNativeQuery("update employee set name=’Alex’ where id = 4");
nativeQuery.unwrap(org.hibernate.SQLQuery.class).addSynchronizedEntityClass(Employee.class);
nativeQuery.executeUpdate();
备注. 本机选择查询不会刷新缓存,只会插入、更新、删除、过程调用等。

手动清除缓存

由于某些原因,您可能想自己从缓存中删除一个对象。这可以通过不同的方式完成。

注意。缓存中的对象存储在称为区域的组中。默认情况下,区域名称与类名称相同。因此,如果您有com.codegym.Employee类型的对象,那么所有这些对象都将存储在名为“ com.codegym.employee ”的组(区域)中。

如果你想访问缓存并用它做一些事情,你可以用 SessionFactory 对象和getCache()方法来完成:

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

如果要从所有组(区域)中删除数据,则需要运行以下查询:

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

要从缓存中删除一个对象,您需要传递其名称(类型)和 ID。您可以通过两种方式执行此操作:

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

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

您还可以检查特定对象是否在缓存中:

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