缓存
缓存的实现不仅需要作为物理介质的硬件,同时需要管理缓存的并发访问策略和过期策略的程序(软件)。所以缓存通常是通过软件和硬件共同实现的。
Hibernate提供了两级缓存,第一级缓存是Session的缓存。由于Session对象的声明周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。
SessionFactory的缓存可分为两类:内置缓存和外置缓存
SessionFactory的内置缓存是Hibernate自带的,不可卸载。通常在Hibernate的初始化阶段,Hibernate会把映射元数据和预定义SQL语句存放到SessionFactory的内置缓存中,映射元数据是映射文件中数据的复制,而预定义SQL语句是Hibernate根据映射元数据推导出来的。SessionFactory的内置缓存是只读缓存,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory无须进行内置缓存与映射文件的同步。
SessionFactory的外置缓存是一个可配置的缓存插件。默认情况下,该缓存插件是关闭的。外置缓存中的数据是数据库数据的复制,外置缓存的物理介质可以是内存或者硬盘。
第一级缓存是必需的,也是不可卸载的。
第二季缓存是可插拔的,它由SessionFactory负责管理。由于SessionFactory对象的生命周期和应用程序的整个进程对应,因此二级缓存是进程范围或集群范围的缓存。
二级缓存中存放的是对象的散装数据。
一级缓存
当应用程序调用Session的save()、update()、saveOrUpdate()、load()、get()方法,以及调用Query查询接口的list()、iterate()或filter()方法时,如果Session的缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中。当清理缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。
二级缓存
在实际中引入缓存(二级缓存)必须考虑的问题
1.数据库是否与其它应用共享
如果是的话,通常意味着可能不得不放弃使用缓存。因为当前应用运行过程中,其它应用可能同时更新数据库。所以这种情况下,缓存策略的指定就需要格外小心。这种情况下,采取一些保守策略(避免缓存机制的使用)可能更加稳妥。
2.应用是否需要部署在集群环境中
这意味着必须考虑是否引入分布式缓存机制,以及引入分布式缓存带来的实际性能变化。
3.对哪些数据应用二级缓存
显然,对数据库中所有的数据都实施缓存是最简单的方法,大多数情况下,这可能是实际开发中最常采用的模式。但某些情况下,这会对性能造成影响。
比如,电信话务系统,客户通过系统可以查询自己的历史通话记录。对于每个客户,库表中可能都有成千上万条数据,而不同客户之间,基本不可能共享数据(客户只查询自身的通话记录),如果对表进行缓存管理,可以想象,内存会迅速被几乎不可能再被重用的数据充斥,系统性能会急剧下降。
因此,在考虑缓存机制应用策略时,我们必须对当前系统 的数据逻辑进行考察,以确定最佳的解决方案。
如果数据满足以下条件,则可将其纳入缓存管理。
- 数据不会被第三方应用修改
- 数据大小在可接受的范围之内
- 数据更新频率低
- 同一数据可能会被系统频繁引用
- 非关键数据(非金融财务数据等)
配置二级缓存主要包含以下步骤:
1.选择需要使用二级缓存的持久化类,设置它的第二级缓存的并发访问策略。
2.选择合适的缓存插件。
每一种缓存插件都自带有配置文件。EHCache缓存的配置文件为ehcache.xml,而JBossCache缓存的配置文件为treecache.xml。
在缓存的配置文件中通常需要为每个第二级缓存设置数据过期策略。
配置进程范围内的二级缓存
以EHCache缓存为例,配置步骤如下。
1.开启hibernate的二级缓存
<!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>
2.指定缓存提供商
<!-- 指定缓存提供商 -->
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
3.指定使用二级缓存的类和集合
这里有两种方式。配置在hbm映射文件中或者配置在hibernate.cfg.xml中。如果使用前者,当映射文件较多时,非常的麻烦。而使用后者,则一目了然,管理方便。
方式一:在每个xx.hbm.xml中配置
Hibernate允许在类和集合上设置第二级缓存。在映射文件中,<class>和<set>元素都有<cache>子元素,这个子元素用来配置第二级缓存。
<cache
usage="transaction|read-write|nonstrict-read-write|read-only"
region="RegionName"
include="all|non-lazy"
/>
usage属性:必须的,指定并发访问策略
region属性:可选的。指定第二级缓存的区域的名字,默认值为类或集合的名字
include属性:可选的。如果取值为non-lazy,表示当缓存一个对象时,不会缓存它的映射为延迟加载(lazy熟悉为true)的属性。默认为all。
方式二:
全部配置到hibernate.cfg.xml中(推荐)<!-- 指定使用二级缓存的类 -->
<class-cache usage="read-write" class="mypack.domain.Customer"/>
<class-cache usage="read-write" class="mypack.domain.Order"/>
<!-- 指定放入二级缓存的集合 -->
<collection-cache usage="read-write" collection="mypack.Customer.orders"/>
4.配置ehcache.xml
<ehcache>
<diskStore path="C:\\temp"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cache name="mypack.Customer"
maxElementsInMemory="1"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
<cache name="mypack.Customer.orders"
maxElementsInMemory="1000"
eternal="true"
overflowToDisk="false"
/>
<cache name="mypack.Order"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
<cache name="customerQueries"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
</ehcache>
<diskStore>元素:缓存数据存放的路径
<defaultCache>元素:缓存的默认过期策略
<cache>元素:设定具体的第二级缓存的数据过期策略。
证明二级缓存存在(起作用)
@Test
public void testSecondLevelCache(){
Session session=HibernateUtils.getSession();
Transaction tx=session.beginTransaction();
Customer c1=(Customer) session.get(Customer.class,2);//放入一级缓存和二级缓
Customer c2=(Customer) session.get(Customer.class,2);//①没发sql。直接从第一级缓存获取
System.out.println(c1==c2);//<1>true
tx.commit();
session.close();//②session关闭,一级缓存消失
session=HibernateUtils.getSession();//新的session
tx=session.beginTransaction();
Customer c3=(Customer) session.get(Customer.class,2);//③没发sql。直接从第二级缓存中获取
System.out.println(c1==c3);//<2>false
}
测试结果:③没有发sql,证明二级缓存起作用了。
注意:<1>处:
结果为true。c1和c2都是从一级缓存中获取的。
<2>处:
结果为false。c1是从一级缓存中获取的,c3是从二级缓存中获取的。
说明:②的作用是排除一级缓存的干扰配置集群范围内的二级缓存
Ehcache适用于Hibernate应用发布在单个机器中的场合。如果企业应用需要支持成千上万的用户的并发访问,会采用
分布式的集群访问方式,可以用JBossCache作为Hibernate的二级缓存。
相关配置这里不具体赘述。
查询缓存
Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存。
对于经常使用的查询语句,如果启用了查询缓存,当第一次执行查询语句时,Hibernate会把查询结果存放在查询缓存中,以后
再次执行该查询语句时,只需从缓存中获得查询结果,从而提高查询性能。
查询缓存适用的场合
- 在应用程序运行中经常使用的查询语句
- 很少对查询语句检索到的数据进行插入、删除或更新操作。
查询缓存使用的步骤
1.配置二级缓存(因为查询缓存是基于二级缓存的)
参考上面ehcache的配置。
2.开启查询缓存
<!-- 开启查询缓存 -->
<property name="cache.use_query_cache">true</property>
3.对于希望启用查询缓存的查询语句, 调用 Query 的 setCacheable(true) 方法
query.setCacheable(true);
证明查询缓存起作用了:
这里为了使结果更清晰,通过对比的形式进行测试。
<1>首先,注释掉①④处@Test
public void testQueryCache(){
Session session=HibernateUtils.getSession();
Transaction tx=session.beginTransaction();
Query query=session.createQuery("from Customer");
//query.setCacheable(true);//①设置查询缓存
query.list();//②放入一级缓存和二级缓存
tx.commit();
session.close();//③session关闭,一级缓存消失
session=HibernateUtils.getSession();
tx=session.beginTransaction();
query=session.createQuery("from Customer");//再次创建Query对象(查询条件相同)
//query.setCacheable(true);//④设置查询缓存
query.list();//⑤发出了sql
tx.commit();
session.close();
}
测试结果:⑤处发出了sql。因为默认情况list()每次都会发出sql语句。
<2>仅注释掉④处@Test
public void testQueryCache(){
Session session=HibernateUtils.getSession();
Transaction tx=session.beginTransaction();
Query query=session.createQuery("from Customer");
query.setCacheable(true);//<span style="font-family: Arial, Helvetica, sans-serif;">①设置查询缓存</span>
query.list();//<span style="font-family: Arial, Helvetica, sans-serif;">②</span>放入一级缓存和二级缓存,放入查询缓存
tx.commit();
session.close();//session关闭,一级缓存消失
session=HibernateUtils.getSession();
tx=session.beginTransaction();
query=session.createQuery("from Customer");//再次创建Query对象(查询条件相同)
//query.setCacheable(true);//④
query.list();//⑤
tx.commit();
session.close();
}
测试结果:⑤处依然发出了sql。
疑问:这时①处设置了查询缓存,为何⑤处依然会发sql?
分析:①处设置了查询缓存,确实执行②时,就会进行查询缓存。但在执行⑤时,由于④处并没有开启,虽然此时存在查询缓存数据,但list()视而不见,依旧查询数据库。
<3>取消①④处的注释@Test
public void testQueryCache(){
Session session=HibernateUtils.getSession();
Transaction tx=session.beginTransaction();
Query query=session.createQuery("from Customer");
query.setCacheable(true);//①设置查询缓存
query.list();//放入一级缓存和二级缓存,放入查询缓存
tx.commit();
session.close();//session关闭,一级缓存消失
session=HibernateUtils.getSession();
tx=session.beginTransaction();
query=session.createQuery("from Customer");//再次创建Query对象(查询条件相同)
query.setCacheable(true);//设置查询缓存
query.list();//⑤
tx.commit();
session.close();
}
测试结果:
⑤处没有发出sql,说明使用了查询缓存。
结论:通过<2>和<3>的测试和分析,可以得知
①的作用:使用查询缓存,为了执行②时将数据缓存到查询缓存中
④的作用:使用查询缓存,为了让5使用②处的查询缓存数据。
遇到的一个DTD问题
hibernate.cfg.xml中配置了二级缓存,还有注册了实体映射关系,但是一直报错。最后根据错误提示,猜测可能是DTD约束的问题,查询DTD的声明才应证了自己的猜测。

结论:
<mapping>必须放在所有的<property>的后面。相关dtd约束如下:
分享到:
相关推荐
总结来说,Hibernate 的一级缓存和二级缓存都是为了提高数据访问效率,但它们在范围和并发控制方面有所不同。一级缓存是事务级别的,保证了数据的强一致性,而二级缓存提供了更多的灵活性,可以跨事务共享,但需要...
《深入理解Hibernate的一级缓存与二级缓存》 Hibernate作为一款强大的ORM框架,其缓存机制是优化数据库操作性能的关键之一。缓存主要分为一级缓存和二级缓存,它们各自承担着不同的职责,共同提升了数据访问的效率...
**hibernate一级缓存、二级缓存和查询缓存** 在Java的持久化框架Hibernate中,缓存机制是提高应用程序性能的关键要素。缓存能够减少数据库的访问次数,提高数据读取速度,并且在一定程度上降低了系统的负载。本文将...
本篇将深入探讨Hibernate的一级缓存和二级缓存,以及查询缓存的配置和使用。 ### 一级缓存 一级缓存是Hibernate默认提供的缓存,它是Session级别的,每个Hibernate Session都有一个私有的、本地的一级缓存。当我们...
Hibernate 一级缓存和二级缓存的区别
标题“Hibernate一级缓存和二级缓存”指的是Hibernate框架中的两种缓存机制,它们是提高数据访问性能的关键要素。一级缓存是Session级别的,而二级缓存是SessionFactory级别的,两者在数据库操作中起到了重要的作用...
本文将深入探讨Hibernate的一级缓存、二级缓存以及查询缓存,通过具体的实例来阐述它们的工作原理和使用方法。 首先,我们从一级缓存开始。一级缓存是Hibernate默认提供的缓存,它是每个Session级别的,也被称为...
本文将详细探讨如何在Spring集成的Hibernate环境中配置二级缓存,以及其背后的原理和实践。 首先,我们需要了解什么是二级缓存。在Hibernate中,一级缓存是每个Session内部的缓存,它自动管理实体的状态,当一个...
本篇文章将深入探讨Hibernate的二级缓存机制,以及如何进行一级缓存与二级缓存的同步,同时还会介绍二级缓存的配置文件设置。 一级缓存是Hibernate默认提供的缓存,每个SessionFactory实例都有一个一级缓存。当对象...
Hibernate二级缓存是一种提高应用程序性能的技术,它将数据存储在SessionFactory级别的缓存中,使得数据可以在不同的Session之间共享。这与一级缓存(Session级别)不同,一级缓存仅存在于单个Session生命周期内,当...
Ehcache 是一个广泛使用的开源缓存解决方案,它支持本地缓存和分布式缓存,与 Hibernate 集成方便,可以提供高效的二级缓存服务。Infinispan 则是一个更强大的内存数据网格,不仅提供缓存功能,还支持数据分布式存储...
在 Hibernate 中,二级缓存和查询缓存是提高应用性能的重要机制。下面将详细介绍如何开启并理解这两个缓存机制。 ### 1. 一级缓存与二级缓存 #### 1.1 一级缓存 一级缓存是 Hibernate 内置的 Session 缓存,它是每...
总的来说,"hibernate二级缓存实例"是一个很好的学习资源,它可以帮助我们理解二级缓存的工作机制,掌握如何在项目中配置和使用,以及注意潜在的问题和优化策略。通过实践,我们可以更好地运用这一技术,提升Java...
在Hibernate框架中,缓存分为一级缓存和二级缓存。 一级缓存是默认开启的,它与Session对象关联,主要负责在同一个事务内部管理对象的状态。一级缓存会跟踪所有在事务中被修改的对象,确保在事务提交时仅生成必要的...
2. **配置Hibernate**:在Hibernate的配置文件`hibernate.cfg.xml`中启用二级缓存并指定缓存提供商。以下是一个使用Ehcache的示例: ```xml <property name="hibernate.cache.use_second_level_cache">true ...
Hibernate 二级缓存是针对SessionFactory级别的全局缓存,与一级缓存(Session级别)不同,一级缓存只在单个Session生命周期内有效。二级缓存则允许不同Session之间共享数据,提高了数据访问效率,减少了对数据库的...
1. **Hibernate二级缓存**:二级缓存是Hibernate在一级缓存(Session级别的缓存)之外提供的全局共享缓存,可以跨Session共享数据。它允许多个并发用户访问相同的数据,减少对数据库的访问次数,提高系统性能。 2. ...
用以介绍hibernate 框架的缓存机制
综上所述,合理配置和使用Hibernate的一级缓存、二级缓存以及查询缓存,能显著提高应用的性能,但需要注意的是,缓存的使用也需要根据具体业务场景和数据更新频率进行调整,以避免出现数据不一致或内存问题。
二级缓存是ORM框架(如Hibernate)中的一个重要特性,它可以在数据库和应用程序之间存储经常访问的数据,以减少对数据库的直接访问,从而提高性能。通常,一级缓存由Hibernate Session管理,而二级缓存则可以跨越多...