缓存(Caching)
缓存是一种增强系统性能的机制。 它是应用程序和数据库之间的缓冲区内存。 高速缓存存储器存储最近使用的数据项,以便尽可能地减少数据库命中的数量。
缓存对Hibernate也很重要。 它使用多级缓存方案,如下所述 -
First-level Cache
第一级缓存是会话缓存,是所有请求必须通过的强制缓存。 Session对象在将对象提交到数据库之前将其保持在自己的权限之下。
如果对对象发出多个更新,Hibernate会尽可能地延迟执行更新以减少发出的更新SQL语句的数量。 如果关闭会话,则缓存的所有对象都将丢失,并在数据库中保留或更新。
Second-level Cache
二级缓存是可选缓存,在尝试在二级缓存中定位对象之前,将始终查询第一级缓存。 可以基于每个类和每个集合配置二级缓存,主要负责跨会话缓存对象。
任何第三方缓存都可以与Hibernate一起使用。 提供了一个org.hibernate.cache.CacheProvider接口,必须实现该接口才能为Hibernate提供缓存实现的句柄。
Query-level Cache
Hibernate还为查询结果集实现了一个缓存,它与二级缓存紧密集成。
这是一个可选功能,需要两个额外的物理缓存区域,用于保存缓存的查询结果和上次更新表时的时间戳。 这仅适用于使用相同参数频繁运行的查询。
二级缓存
Hibernate默认使用第一级缓存,而您无需使用第一级缓存。 让我们直接进入可选的二级缓存。 并非所有类都受益于缓存,因此能够禁用二级缓存非常重要。
Hibernate二级缓存分两步设置。 首先,您必须决定使用哪种并发策略。 之后,使用缓存提供程序配置缓存过期和物理缓存属性。
并发策略
并发策略是一个中介,它负责在缓存中存储数据项并从缓存中检索它们。 如果要启用二级缓存,则必须为每个持久化类和集合决定使用哪种缓存并发策略。
Transactional - 在极少数更新的情况下,将此策略用于读取主要数据,这对于防止并发事务中的过时数据至关重要。
Read-write - 再次将此策略用于读取主要数据,在这种情况下,在极少数情况下更新时,防止并发事务中的陈旧数据至关重要。
Nonstrict-read-write - 此策略不保证缓存和数据库之间的一致性。 如果数据几乎没有变化,并且过时数据的可能性很小,则不要使用此策略。
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/>
</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强制您为整个应用程序选择单个缓存提供程序。
Sr.No. | 缓存名称和描述 |
---|---|
1 | EHCache 它可以缓存在内存或磁盘和集群缓存中,它支持可选的Hibernate查询结果缓存。 |
2 | OSCache 支持在单个JVM中缓存到内存和磁盘,并具有丰富的过期策略和查询缓存支持。 |
3 | warmCache 基于JGroups的集群高速缓存。 它使用群集失效,但不支持Hibernate查询缓存。 |
4 | JBoss Cache 完全事务复制的群集缓存,也基于JGroups多播库。 它支持复制或失效,同步或异步通信以及乐观和悲观锁定。 支持Hibernate查询缓存。 |
每个缓存提供程序都与每个并发策略都不兼容。 以下兼容性矩阵将帮助您选择合适的组合。
战略/供应商 | 只读 | Nonstrictread写 | 读写 | 交易 |
---|---|---|---|---|
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 ,它应该位于应用程序的CLASSPATH中。 在Employe类的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在缓存的employee区域中存储和查找查询。