Hibernate - 缓存



缓存是一种增强系统性能的机制。它是一个位于应用程序和数据库之间的缓冲内存。缓存内存存储最近使用的数据项,以便尽可能减少数据库访问次数。

缓存对 Hibernate 也很重要。它利用了如下所述的多级缓存方案:

Hibernate Caching

一级缓存

一级缓存是 Session 缓存,是所有请求都必须经过的强制缓存。Session 对象在将对象提交到数据库之前,会将其保留在自己控制之下。

如果您对某个对象发出多个更新操作,Hibernate 会尝试尽可能延迟执行更新操作,以减少发出的更新 SQL 语句的数量。如果您关闭 Session,则所有正在缓存的对象都会丢失,并在数据库中持久化或更新。

二级缓存

二级缓存是可选缓存,在尝试在二级缓存中查找对象之前,始终会先查询一级缓存。二级缓存可以在每个类和每个集合的基础上进行配置,主要负责跨 Session 缓存对象。

任何第三方缓存都可以与 Hibernate 一起使用。提供了org.hibernate.cache.CacheProvider接口,必须实现该接口才能为 Hibernate 提供缓存实现的句柄。

查询级缓存

Hibernate 还为查询结果集实现了缓存,该缓存与二级缓存紧密集成。

这是一个可选功能,需要两个额外的物理缓存区域来保存缓存的查询结果以及上次更新表的时间戳。这仅适用于经常使用相同参数运行的查询。

二级缓存

Hibernate 默认使用一级缓存,您无需执行任何操作即可使用一级缓存。让我们直接进入可选的二级缓存。并非所有类都受益于缓存,因此能够禁用二级缓存非常重要。

Hibernate 二级缓存的设置分为两个步骤。首先,您必须决定使用哪种并发策略。之后,您使用缓存提供程序配置缓存过期和物理缓存属性。

并发策略

并发策略是一种中介,负责将数据项存储在缓存中并从缓存中检索它们。如果您要启用二级缓存,则必须为每个持久化类和集合决定使用哪种缓存并发策略。

  • 事务型 - 在很少出现更新的情况下,对于主要用于读取的数据,如果关键是要防止并发事务中的陈旧数据,请使用此策略。

  • 读写型 - 在很少出现更新的情况下,对于主要用于读取的数据,如果关键是要防止并发事务中的陈旧数据,请再次使用此策略。

  • 非严格读写型 - 此策略不保证缓存和数据库之间的一致性。如果数据几乎从不更改并且出现少量陈旧数据的可能性并不关键,请使用此策略。

  • 只读型 - 适用于从不更改数据的并发策略。仅对参考数据使用它。

如果我们要对Employee类使用二级缓存,让我们添加所需的映射元素来告诉 Hibernate 使用读写策略缓存 Employee 实例。

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping>
   <class name = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <cache usage = "read-write"/>
      
      <id name = "id" type = "int" column = "id">
         <generator class="native"/>
      </id>
      
      <property name = "firstName" column = "first_name" type = "string"/>
      <property name = "lastName" column = "last_name" type = "string"/>
      <property name = "salary" column = "salary" type = "int"/>
      
   </class>
</hibernate-mapping>

usage="read-write"属性告诉 Hibernate 对定义的缓存使用读写并发策略。

缓存提供程序

在考虑了并发策略之后,下一步是使用缓存候选类选择缓存提供程序。Hibernate 强制您为整个应用程序选择一个缓存提供程序。

序号 缓存名称和描述
1

EHCache

它可以缓存到内存或磁盘,并支持集群缓存,并且支持可选的 Hibernate 查询结果缓存。

2

OSCache

支持将缓存到单个 JVM 中的内存和磁盘,并具有丰富的过期策略和查询缓存支持。

3

warmCache

基于 JGroups 的集群缓存。它使用集群失效,但不支持 Hibernate 查询缓存。

4

JBoss Cache

一个完全事务性的复制集群缓存,也基于 JGroups 多播库。它支持复制或失效、同步或异步通信以及乐观和悲观锁定。支持 Hibernate 查询缓存。

并非每个缓存提供程序都与每种并发策略兼容。以下兼容性矩阵将帮助您选择合适的组合。

策略/提供程序 只读型 非严格读写型 读写型 事务型
EHCache X X X  
OSCache X X X  
SwarmCache X X    
JBoss Cache X     X

您将在 hibernate.cfg.xml 配置文件中指定缓存提供程序。我们选择 EHCache 作为我们的二级缓存提供程序:

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
   <session-factory>
   
      <property name = "hibernate.dialect">
         org.hibernate.dialect.MySQLDialect
      </property>
   
      <property name = "hibernate.connection.driver_class">
         com.mysql.jdbc.Driver
      </property>
   
      <!-- Assume students is the database name -->
   
      <property name = "hibernate.connection.url">
         jdbc:mysql://127.0.0.1/test
      </property>
   
      <property name = "hibernate.connection.username">
         root
      </property>
   
      <property name = "hibernate.connection.password">
         root123
      </property>
   
      <property name = "hibernate.cache.provider_class">
         org.hibernate.cache.EhCacheProvider
      </property>
   
      <!-- List of XML mapping files -->
      <mapping resource = "Employee.hbm.xml"/>
   
   </session-factory>
</hibernate-configuration>

现在,您需要指定缓存区域的属性。EHCache 有自己的配置文件ehcache.xml,该文件应该位于应用程序的 CLASSPATH 中。ehcache.xml 中 Employee 类的缓存配置可能如下所示:

<diskStore path="java.io.tmpdir"/>

<defaultCache
maxElementsInMemory = "1000"
eternal = "false"
timeToIdleSeconds = "120"
timeToLiveSeconds = "120"
overflowToDisk = "true"
/>

<cache name = "Employee"
maxElementsInMemory = "500"
eternal = "true"
timeToIdleSeconds = "0"
timeToLiveSeconds = "0"
overflowToDisk = "false"
/>

就是这样,现在我们为 Employee 类和 Hibernate 启用了二级缓存,现在只要您导航到 Employee 或按标识符加载 Employee 时,Hibernate 就会命中二级缓存。

您应该分析所有类并为每个类选择合适的缓存策略。有时,二级缓存可能会降低应用程序的性能。因此,建议您首先在不启用缓存的情况下对应用程序进行基准测试,然后启用适合您的缓存并检查性能。如果缓存没有提高系统性能,则启用任何类型的缓存都没有意义。

查询级缓存

要使用查询缓存,您必须首先使用配置文件中的hibernate.cache.use_query_cache="true"属性激活它。通过将此属性设置为 true,您可以使 Hibernate 在内存中创建必要的缓存来保存查询和标识符集。

接下来,要使用查询缓存,您可以使用 Query 类的 setCacheable(Boolean)方法。例如:

Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
List users = query.list();
SessionFactory.closeSession();

Hibernate 还通过缓存区域的概念支持非常细粒度的缓存支持。缓存区域是缓存的一部分,并被赋予一个名称。

Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
query.setCacheRegion("employee");
List users = query.list();
SessionFactory.closeSession();

此代码使用该方法告诉 Hibernate 将查询存储在缓存的 employee 区域中并从中查找查询。

广告