缓存可以简单的看成一个 Map ,通过 key 在缓存里面找 value 。
一、缓存简介 Cache In Hibernate
HIBERNATE 中的 CACHE 有两级 .
一级是在 Session 范围内的 CACHE . 即每个 Session 有自己的一个 CACHE, 当前操作的对象都会被保留在 CACHE 中 . 但是 Session 关闭后这个 CACHE 也就没有 . 可见这级 CACHE 的生命期是很短的 . (使用 id 进行关键字存储:缓存的 key 就是 ID , value 是 POJO ) ( 缓存的是实体对象 )
另一级 CACHE 是在 SessionFactory 范围的 , 可以被来自同一个 SessionFactory 的 Session 共享 . 在 HIBERNATE 的文档中称其为 SECOND LEVEL CACHE. 显然后者的优势较明显 , 也比较复合当前的使用环境 . 它可以使用不同的缓存实现,如 EhCache 、 JBossCache 、 OsCache 等 (二级缓存是缓存实体对象的)
还有一个类型的 CACHE 就是 QueryCache . 它的作用就是缓存一个 Query 以及 Query 返回对象的 Identifier 以及对象的类型 . 有了 QueryCache 后就可以高效的使用 SECOND LEVEL CACHE.
hibernate 查询缓存 (hibernate 默认是关闭的 )
查询缓存是针对普通属性结果集的缓存
对实体对象的结果集只缓存 id
查询缓存的生命周期,当前关联的表发生修改,那么查询缓存生命周期结束
查询缓存的配置和使用:
1. 启用查询缓存:在 hibernate .cfg.xml 中加入:
<property name=”hibernate .cache.use_query_cache”>true</property>
2. 在程序中必须手动启用查询缓存,如: query.setCacheable(true);
QueryCache 用来缓存查询语句 , 及查询结果集中对象的 Identifier 与 Type. 当再次使用已缓存的 Query 时 , 就可以通过对象的 Identifier 与 Type 在 SECOND LEVEL CACHE 中查找实际的对象 .
对于查询缓存来说,缓存的 key 是根据 hql 生成的 sql ,再加上参数,分页等信息(可以通过日志输出看到,不过它的输出不是很可读,最好改一下它的代码)。
注:一级缓存也叫 session 级的缓存或事务缓存。 Hibernate 二级缓存也称为进程级的缓存或 SessionFactory 级的缓存。二级缓存是全局缓存,它可以被所有的 session 共享。二级缓存的生命周期和 SessionFactory 的生命周期一致, SessionFactory 可以管理二级缓存。
二、缓存的范围
缓存的范围分为 3 类 :
1. 事务范围
事务范围的缓存只能被当前事务访问 , 每个事务都有各自的缓存 , 缓存内的数据通常采用相互关联的对象形式 . 缓存的生命周期依赖于事务的生命周期 , 只有当事务结束时 , 缓存的生命周期才会结束 . 事务范围的缓存使用内存作为存储介质 , 一级缓存就属于事务范围 .
2. 应用范围
应用程序的缓存可以被应用范围内的所有事务共享访问 . 缓存的生命周期依赖于应用的生命周期 , 只有当应用结束时 , 缓存的生命周期才会结束 . 应用范围的缓存可以使用内存或硬盘作为存储介质 , 二级缓存就属于应用范围 .
3. 集群范围
在集群环境中 , 缓存被一个机器或多个机器的进程共享 , 缓存中的数据被复制到集群环境中的每个进程节点 , 进程间通过远程通信来保证缓存中的数据的一致 , 缓存中的数据通常采用对象的松散数据形式 .
三、缓存的方式
有四种,分别为:
CacheConcurrencyStrategy.NONE
CacheConcurrencyStrategy.READ_ONLY ,只读模式,在此模式下,如果对数据进行更新操作,会有异常;
CacheConcurrencyStrategy.READ_WRITE ,读写模式在更新缓存的时候会把缓存里面的数据换成一个锁,其它事务如果去取相应的缓存数据,发现被锁了,直接就去数据库查询;
CacheConcurrencyStrategy.NONSTRICT_READ_WRITE ,不严格的读写模式则不会的缓存数据加锁;
CacheConcurrencyStrategy.TRANSACTIONAL ,事务模式指缓存支持事务,当事务回滚时,缓存也能回滚,只支持 JTA 环境。
缓存的注释写法如下,加在 Entity 的 java 类上:
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
四、缓存的管理
Hibernate 的缓存管理
一级缓存的管理 :
evit(Object obj) 将指定的持久化对象从一级缓存中清除 , 释放对象所占用的内存资源 , 指定对象从持久化状态变为脱管状态 , 从而成为游离对象 .
clear() 将一级缓存中的所有持久化对象清除 , 释放其占用的内存资源
contains(Object obj) 判断指定的对象是否存在于一级缓存中 .
flush() 刷新一级缓存区的内容 , 使之与数据库数据保持同步 .
二级缓存的管理 :
evict(Class arg0, Serializable arg1) 将某个类的指定 ID 的持久化对象从二级缓存中清除 , 释放对象所占用的资源 .
evictCollection(String arg0) 将指定类的所有持久化对象的指定集合从二级缓存中清除 , 释放其占用的内存资源 .
如何避免一次性大量的实体数据入库导致内存溢出
* 先 flush ,再 clear
如果数据量特别大,考虑采用 jdbc 实现,如果 jdbc 也不能满足要求,可以考虑采用数据库本身的特定导入工具
五、什么样的数据不适合放在二级缓存中来 ?
下面这几种情况就不适合 加载到二级缓存中 :
1. 经常被修改的数据
2. 绝对不允许出现并发访问的数据
3. 与其他应用共享的数据
下面这己种情况合适 加载到二级缓存中 :
1. 数据更新频率低
2. 允许偶尔出现并发问题的非重要数据
3. 不会被并发访问的数据
4. 常量数据
5. 不会被第三方修改的数据
六、二级缓存的配置
Hibernate 的二级缓存功能是靠配置二级缓存插件来实现的 ,Hibernate 为了集成这些插件 ,Hibernate 提供了 org.hibernate.cache.CacheProvider 借口 , 它充当缓存插件与 Hibernate 之间的适配器 .
常用的二级缓存插件
EHCache org.hibernate.cache.EhCacheProvider
OSCache org.hibernate.cache.OSCacheProvider
SwarmCahe org.hibernate.cache.SwarmCacheProvider
JBossCache org.hibernate.cache.TreeCacheProvider
设置 hibernate.cache.provider_class 。
我们这里用 ehcache ,如
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
由于这是 HIBERNATE 默认的 CACHE 提供者 , 所以无须做什么设置 .
只要在 src 中添加 ehcache 的配置文件 ehcache.xml:
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" />
<cache name="goncha.hb.bean.Person" maxElementsInMemory="10" eternal="false"
timeToIdleSeconds="100" timeToLiveSeconds="100" overflowToDisk="false" />
<cache name="goncha.hb.bean.Address" maxElementsInMemory="10" eternal="false"
timeToIdleSeconds="100" timeToLiveSeconds="100" overflowToDisk="false" />
</ehcache>
七、哪些方法支持缓存
*get()
*load()
*iterate() ( 查询实体对象 )
save()
查询缓存只对 query.list() 起作用
一级缓存测试:
1 . Load 测试 : 在同一个 session 中发出两次 load 查询( 1 )
2 . Get 测试 : 在同一个 session 中发出两次 get 查询( 1 )
3 . iterate 测试 : 在同一个 session 中发出两次 iterator 查询( 1 ( id ) +N , 1 ( id ))
4 . Iterate 查询属性测试 : 同一个 session 中发出两次查询属性( 2 次, iterate 查询普通属性,一级缓存不会缓存,所以会发出 sql )
5 .同一个 session 中先 save ,再发出 load 查询 save 过的数据 --save 是使用缓存的
6 .同一个 session 中先调用 load 查询,然后执行 sessio.clear() 或 session.evict() ,再调用 load 查询( 2 次)
sessio.clear() 或 session.evict() 可以管理一级缓存,一级缓存无法取消,但可以管理 . 上面的语句都会发出 sql 因为一级缓存中的实体被清除了
7 .向数据库中批量加入 1000 条数据
// 每一定条数据就强制 session 将数据持久化,同时清除缓存,避免大量数据造成内存溢出
开启二级缓存测试:
1 .开启两个 session 中发出两次 load 查询( get 与 load 一样, 1 次) ,
2 .开启两个 session ,分别调用 load ,再使用 sessionFactory 清楚二级缓存( 2 次)
3 .一级缓存和二级缓存的交互
session.setCacheMode(CacheMode.GET); // 设置成 只是从二级缓存里读 , 不向二级缓存里写数据 ( 2 )
session.setCacheMode(CacheMode.PUT); // 设置成只是向二级缓存里写数据,不读数据 ( 2 次)
开启 hibernate 查询缓存测试:
1 . 开启查询缓存,关闭二级缓存,开启一个 session ,分别调用 query.list (查询属性)( 1 次)
2 . 开启查询缓存,关闭二级缓存,开启两个 session ,分别调用 query.list (查询属性)
( 1 次)第二次没有去查询数据库,因为查询缓存生命周期与 session 生命周期无关
3 . 开启查询缓存,关闭二级缓存,开启两个 session ,分别调用 query.iterate (查询属性)
( 2 次)第二去查询数据库,因为查询缓存只对 query.list() 起作用,对 query.iterate() 不起作用 , 也就是说 query.iterate() 不使用查询缓存
4 . 关闭查询缓存,关闭二级缓存,开启两个 session ,分别调用 query.list (查询实体对象) 第二去查询数据库,因为 list 默认每次都会发出查询 sql
5 . 开启查询缓存,关闭二级缓存,开启两个 session ,分别调用 query.list (查询实体对象) 第二去查询数据库时,会发出 N 条 sql 语句,因为开启了查询缓存,关闭了二级缓存,那么查询缓存会缓存实体对象的 id ,所以 hibernate 会根据实体对象的 id 去查询相应的实体,如果缓存中不存在相应的实体,那么将发出根据实体 id 查询的 sql 语句,否则不会发出 sql ,使用缓存中的数据
6 . 开启查询缓存,开启二级缓存,开启两个 session ,分别调用 query.list (查询实体对象) 第二不会发出 sql ,因为开启了二级缓存和查询缓存,查询缓存缓存了实体对象的 id 列表, hibernate 会根据实体对象的 id 列表到二级缓存中取得相应的数据
八、二级缓存在项目中的集成和使用
1. 将 echcache.xml 文件拷贝到 src 下 , 二级缓存 hibernate 默认是关闭的,手动开启
2. 开启二级缓存,修改 hibernate .cfg.xml 文件 ,
<property name=”hibernate .cache.user_second_level_cache”>true</property>
3. 指定缓存产品提供商
<property name=”hibernate .cache.provider_calss”>org.hibernate .cache.EhCacheProvider</property>
4. 指定那些实体类使用二级缓存(两种方法,推荐使用第二种)
第一种:在 *.hbm.xml 中,在 <id> 之前加入
<cache usage=”read-only” />, 使用二级缓存
第二种:在 hibernate .cfg.xml 配置文件中 , 在 <mapping resource=”com/Studnet.hbm.xml” /> 后面 加上:
<class-cache class=” com.Studnet” usage=”read-only” />
总结:
不要想当然的以为缓存一定能提高性能,仅仅在你能够驾驭它并且条件合适的情况下才是这样的。 hibernate 的二级缓存限制还是比较多的,不方便用 jdbc 可能会大大的降低更新性能。在不了解原理的情况下乱用,可能会有 1+N 的问题。不当的使用还可能导致读出脏数据。
如果受不了 hibernate 的诸多限制,那么还是自己在应用程序的层面上做缓存吧。
在越高的层面上做缓存,效果就会越好 。就好像尽管磁盘有缓存,数据库还是要实现自己的缓存,尽管数据库有缓存,咱们的应用程序还是要做缓存。因为底层的缓存它并不知道高层要用这些数据干什么,只能做的比较通用,而高层可以有针对性的实现缓存,所以在更高的级别上做缓存,效果也要好些吧。
对于性能的看法是:合理的性能而不是最高的性能。什么是合理的?用户能感觉到(或敏感的)的范围内,不成为物理上业务处理的瓶颈,比如常说的 3 秒之内响应等。
[/size][/size][/size]
分享到:
相关推荐
Hibernate缓存.docHibernate缓存.doc
**Hibernate缓存深入详解** 在Java企业级应用开发中,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。然而,随着应用规模的扩大,数据访问性能成为了一个不可忽视的问题。这时,...
### Hibernate缓存技术研究 #### 一、引言 Hibernate是一种强大的对象-关系映射(Object-Relational Mapping,简称ORM)工具,主要用于Java环境下的应用程序。它能够将应用程序中的对象模型映射到关系型数据库的表...
Java Hibernate缓存深入详解
Hibernate缓存机制是提高应用程序性能的关键技术之一,它通过存储数据副本减少对物理数据库的访问。缓存可以分为两层:第一级缓存和第二级缓存。 **第一级缓存**是内置在Session中的,它是不可卸载的,也称为...
关于hibernate缓存的一个ppt课件,60+幻灯片,有需要的可以看一下
本文将深入探讨Hibernate缓存的原理、类型及其对性能优化的影响。 ### Hibernate缓存原理 Hibernate缓存主要分为一级缓存和二级缓存。一级缓存,也称为会话缓存(Session Cache),是默认启用的,由Hibernate自动...
【Hibernate缓存深入详解】 在Java的持久化框架Hibernate中,缓存机制是提升系统性能的关键因素。它位于Hibernate应用和数据库之间,减少了对数据库的直接访问,从而提高了应用程序的运行速度。缓存中存储的是...
**标题:“Hibernate缓存与Spring事务详解”** 在IT领域,尤其是Java开发中,Hibernate作为一款流行的ORM(对象关系映射)框架,极大地简化了数据库操作。而Spring框架则以其全面的功能,包括依赖注入、AOP(面向切...
Hibernate 是一个流行的对象关系映射(ORM)框架,它允许Java...通过理解Hibernate缓存和事务管理,以及如何有效地执行查询,开发者可以创建高效、健壮的Java应用程序,降低与数据库交互的复杂性,同时提升系统性能。
### Hibernate缓存机制及优化策略 #### 一、概述 Hibernate作为一款优秀的对象关系映射(ORM)框架,在Java开发领域被广泛应用于数据库操作。它提供了丰富的缓存机制来提高应用性能并降低数据库访问压力。本文将...
Hibernate缓存原理及调优策略 Hibernate缓存原理调优策略
**Hibernate缓存详解** 在Java开发中,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。为了提高数据访问性能,Hibernate引入了缓存机制,它可以减少对数据库的直接访问,从而提升应用的...
这篇博客文章“hibernate缓存ehcache用法”可能详细介绍了如何在Hibernate中配置和使用Ehcache。 首先,我们需要理解什么是缓存。缓存是一种存储技术,用于临时保存经常访问的数据,以减少对主存储器(如数据库)的...
**标题解析:** "Hibernate教程25_Hibernate缓存" 这个标题表明了我们要讨论的是关于Hibernate框架的第25个教程,重点是它的缓存机制。Hibernate是一个流行的Java对象关系映射(ORM)框架,它允许开发者用面向对象的...
hibernate缓存深入详解