Hibernate - 缓存


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

缓存对于 Hibernate 也很重要。它利用多级缓存方案,如下所述 -

Hibernate缓存

一级缓存

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

如果您对一个对象发出多次更新,Hibernate 会尝试尽可能延迟执行更新,以减少发出的更新 SQL 语句的数量。如果关闭会话,所有缓存的对象都会丢失,并在数据库中保留或更新。

二级缓存

二级缓存是可选的缓存,在尝试在二级缓存中定位对象之前,将始终查询一级缓存。二级缓存可以按类和按集合进行配置,主要负责跨会话缓存对象。

任何第三方缓存都可以与 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>

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

缓存提供者

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

先生。 缓存名称和描述
1

超高速缓存

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

2

操作系统缓存

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

3

热缓存

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

4

JBoss缓存

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

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

策略/提供商 只读 非严格读写 读写 交易性
超高速缓存 X X X  
操作系统缓存 X X X  
群缓存 X X    
JBoss缓存 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,该文件应该位于应用程序的 CLASSPATH 中。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 时都会访问二级缓存。

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

查询级缓存

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