Hibernate 简明教程

Hibernate - Caching

高速缓存是一种增强系统性能的机制。它是一种位于应用程序和数据库之间的缓冲存储器。高速缓存存储最近使用过的数据项,尽可能减少数据库命中次数。

高速缓存对 Hibernate 也很重要。它利用了如下解释的多级高速缓存方案——

hibernate cache

First-level Cache

一级高速缓存即 Session 高速缓存,这是一个所有请求都必须经过的强制高速缓存。Session 对象在将对象提交到数据库之前,在自己的能力范围内保留该对象。

如果对对象发出多次更新,Hibernate 尝试尽可能长时间延迟更新,以减少发出的更新 SQL 语句的次数。如果关闭 Session,所有被缓存的对象都会丢失并且被保留或更新到数据库中。

Second-level Cache

二级高速缓存是一个可选的高速缓存,而且在尝试定位二级高速缓存中的对象之前,通常会咨询一级高速缓存。二级高速缓存可以在每个类和每个集合的基础上配置,并且主要负责跨 Session 缓存对象。

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

Query-level Cache

Hibernate 还为查询结果集实现了与二级缓存紧密集成在一起的缓存。

这是一个可选特性,需要两个附加的物理缓存区域来保存缓存的查询结果以及表上次更新的时间戳。这仅适用于频繁使用相同参数运行的查询。

The Second Level Cache

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

Hibernate 二级缓存分两步设置。首先,您必须决定使用哪种并发策略。然后,使用缓存提供程序配置缓存到期时间和物理缓存属性。

Concurrency Strategies

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

  1. Transactional − 在并发事务中,对于更新这种情况不太可能发生时,防止陈旧数据至关重要的几乎只读数据,请使用此策略。

  2. Read-write − 在并发事务中,对于更新这种情况不太可能发生时,防止陈旧数据至关重要的几乎只读数据,请再次使用此策略。

  3. Nonstrict-read-write − 此策略不保证缓存和数据库之间的一致性。如果数据几乎从不更改,并且陈旧数据的可能很小,请使用此策略,在这种情况下,陈旧数据不是严重的问题。

  4. Read-only − 适用于永不更改的数据的并发策略。仅将其用于引用数据。

如果我们准备为 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 为定义的缓存使用读写并发策略。

Cache Provider

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

Sr.No.

Cache Name & Description

1

EHCache 它可以在内存中或磁盘上进行缓存,支持集群缓存,并支持可选的 Hibernate 查询结果缓存。

2

OSCache 支持在单个 JVM 中将数据缓存到内存和磁盘,并提供丰富的到期策略和查询缓存支持。

3

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

4

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

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

Strategy/Provider

Read-only

Nonstrictread-write

Read-write

Transactional

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://localhost/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 ,它应该在应用程序的类路径中。Employee 类的 ehcache.xml 中的缓存配置可能如下所示:

<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 时,都会命中二级缓存。

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

The Query-level Cache

要使用查询缓存,你必须首先使用配置文件中的 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 区域中并查找该查询。