原文链接:http://blog.csdn.net/woshichenxu/article/details/586361#t0

1.     关于hibernate缓存的问题:

1.1.1.         基本的缓存原理

Hibernate缓存分为二级,第一级存放于session中称为一级缓存,默认带有且不能卸载。

第二级是由sessionFactory控制的进程级缓存。是全局共享的缓存,凡是会调用二级缓存的查询方法 都会从中受益。只有经正确的配置后二级缓存才会发挥作用。同时在进行条件查询时必须使用相应的方法才能从缓存中获取数据。比如Query.iterate()方法、load、get方法等。必须注意的是session.find方法永远是从数据库中获取数据,不会从二级缓存中获取数据,即便其中有其所需要的数据也是如此。

查询时使用缓存的实现过程为:首先查询一级缓存中是否具有需要的数据,如果没有,查询二级缓存,如果二级缓存中也没有,此时再执行查询数据库的工作。要注意的是:此3种方式的查询速度是依次降低的。

1.2.   存在的问题

1.2.1.      一级缓存的问题以及使用二级缓存的原因

因为Session的生命期往往很短,存在于Session内部的第一级最快缓存的生命期当然也很短,所以第一级缓存的命中率是很低的。其对系统性能的改善也是很有限的。当然,这个Session内部缓存的主要作用是保持Session内部数据状态同步。并非是hibernate为了大幅提高系统性能所提供的。

为了提高使用hibernate的性能,除了常规的一些需要注意的方法比如:

使用延迟加载、迫切外连接、查询过滤等以外,还需要配置hibernate的二级缓存。其对系统整体性能的改善往往具有立竿见影的效果!

(经过自己以前作项目的经验,一般会有3~4倍的性能提高)

1.2.2.      N+1次查询的问题

执行条件查询时,iterate()方法具有著名的 “n+1”次查询的问题,也就是说在第一次查询时iterate方法会执行满足条件的查询结果数再加一次(n+1)的查询。但是此问题只存在于第一次查询时,在后面执行相同查询时性能会得到极大的改善。此方法适合于查询数据量较大的业务数据。

但是注意:当数据量特别大时(比如流水线数据等)需要针对此持久化对象配置其具体的缓存策略,比如设置其存在于缓存中的最大记录数、缓存存在的时间等参数,以避免系统将大量的数据同时装载入内存中引起内存资源的迅速耗尽,反而降低系统的性能!!!

1.3.   使用hibernate二级缓存的其他注意事项:

1.3.1.      关于数据的有效性

另外,hibernate会自行维护二级缓存中的数据,以保证缓存中的数据和数据库中的真实数据的一致性!无论何时,当你调用save()、update()或 saveOrUpdate()方法传递一个对象时,或使用load()、 get()、list()、iterate() 或scroll()方法获得一个对象时, 该对象都将被加入到Session的内部缓存中。 当随后flush()方法被调用时,对象的状态会和数据库取得同步。

也就是说删除、更新、增加数据的时候,同时更新缓存。当然这也包括二级缓存!

只要是调用hibernate API执行数据库相关的工作。hibernate都会为你自动保证 缓存数据的有效性!!

但是,如果你使用了JDBC绕过hibernate直接执行对数据库的操作。此时,Hibernate不会/也不可能自行感知到数据库被进行的变化改动,也就不能再保证缓存中数据的有效性!!

这也是所有的ORM产品共同具有的问题。幸运的是,Hibernate为我们暴露了Cache的清除方法,这给我们提供了一个手动保证数据有效性的机会!!

一级缓存,二级缓存都有相应的清除方法。

其中二级缓存提供的清除方法为:

按对象class清空缓存

按对象class和对象的主键id清空缓存

清空对象的集合中的缓存数据等。

1.3.2.      适合使用的情况

并非所有的情况都适合于使用二级缓存,需要根据具体情况来决定。同时可以针对某一个持久化对象配置其具体的缓存策略。

适合于使用二级缓存的情况:

1、数据不会被第三方修改;

一般情况下,会被hibernate以外修改的数据最好不要配置二级缓存,以免引起不一致的数据。但是如果此数据因为性能的原因需要被缓存,同时又有可能被第3方比如SQL修改,也可以为其配置二级缓存。只是此时需要在sql执行修改后手动调用cache的清除方法。以保证数据的一致性

2、数据大小在可接收范围之内;

如果数据表数据量特别巨大,此时不适合于二级缓存。原因是缓存的数据量过大可能会引起内存资源紧张,反而降低性能。

如果数据表数据量特别巨大,但是经常使用的往往只是较新的那部分数据。此时,也可为其配置二级缓存。但是必须单独配置其持久化类的缓存策略,比如最大缓存数、缓存过期时间等,将这些参数降低至一个合理的范围(太高会引起内存资源紧张,太低了缓存的意义不大)。

3、数据更新频率低;

对于数据更新频率过高的数据,频繁同步缓存中数据的代价可能和 查询缓存中的数据从中获得的好处相当,坏处益处相抵消。此时缓存的意义也不大。

4、非关键数据(不是财务数据等)

财务数据等是非常重要的数据,绝对不允许出现或使用无效的数据,所以此时为了安全起见最好不要使用二级缓存。

因为此时 “正确性”的重要性远远大于 “高性能”的重要性。

2.     目前系统中使用hibernate缓存的建议

1.4.   目前情况

一般系统中有三种情况会绕开hibernate执行数据库操作:

1、多个应用系统同时访问一个数据库

此种情况使用hibernate二级缓存会不可避免的造成数据不一致的问题,

此时要进行详细的设计。比如在设计上避免对同一数据表的同时的写入操作,

使用数据库各种级别的锁定机制等。

2、动态表相关

所谓“动态表”是指在系统运行时根据用户的操作系统自动建立的数据表。

比如“自定义表单”等属于用户自定义扩展开发性质的功能模块,因为此时数据表是运行时建立的,所以不能进行hibernate的映射。因此对它的操作只能是绕开hibernate的直接数据库JDBC操作。

如果此时动态表中的数据没有设计缓存,就不存在数据不一致的问题。

如果此时自行设计了缓存机制,则调用自己的缓存同步方法即可。

3、使用sql对hibernate持久化对象表进行批量删除时

此时执行批量删除后,缓存中会存在已被删除的数据。

分析:

当执行了第3条(sql批量删除)后,后续的查询只可能是以下三种方式:

a. session.find()方法:

根据前面的总结,find方法不会查询二级缓存的数据,而是直接查询数据库。

所以不存在数据有效性的问题。

b. 调用iterate方法执行条件查询时:

根据iterate查询方法的执行方式,其每次都会到数据库中查询满足条件的id值,然后再根据此id到缓存中获取数据,当缓存中没有此id的数据才会执行数据库查询;

如果此记录已被sql直接删除,则iterate在执行id查询时不会将此id查询出来。所以,即便缓存中有此条记录也不会被客户获得,也就不存在不一致的情况。(此情况经过测试验证)

c. 用get或load方法按id执行查询:

客观上此时会查询得到已过期的数据。但是又因为系统中执行sql批量删除一般是

针对中间关联数据表,对于

中间关联表的查询一般都是采用条件查询 ,按id来查询某一条关联关系的几率很低,所以此问题也不存在!

如果某个值对象确实需要按id查询一条关联关系,同时又因为数据量大使用 了sql执行批量删除。当满足此两个条件时,为了保证按id 的查询得到正确的结果,可以使用手动清楚二级缓存中此对象的数据的方法!!

(此种情况出现的可能性较小)

1.5.   建议

1、建议不要使用sql直接执行数据持久化对象的数据的更新,但是可以执行 批量删除。(系统中需要批量更新的地方也较少)

2、如果必须使用sql执行数据的更新,必须清空此对象的缓存数据。调用

SessionFactory.evict(class)

SessionFactory.evict(class,id)

等方法。

3、在批量删除数据量不大的时候可以直接采用hibernate的批量删除,这样就不存在绕开hibernate执行sql产生的缓存数据一致性的问题。

4、不推荐采用hibernate的批量删除方法来删除大批量的记录数据。

原因是hibernate的批量删除会执行1条查询语句外加 满足条件的n条删除语句。而不是一次执行一条条件删除语句!!

当待删除的数据很多时会有很大的性能瓶颈!!!如果批量删除数据量较大,比如超过50条,可以采用JDBC直接删除。这样作的好处是只执行一条sql删除语句,性能会有很大的改善。同时,缓存数据同步的问题,可以采用 hibernate清除二级缓存中的相关数据的方法。

调用 SessionFactory.evict(class) ;SessionFactory.evict(class,id)等方法。

所以说,对于一般的应用系统开发而言(不涉及到集群,分布式数据同步问题等),因为只在中间关联表执行批量删除时调用了sql执行,同时中间关联表一般是执行条件查询不太可能执行按id查询。所以,此时可以直接执行sql删除,甚至不需要调用缓存的清除方法。这样做不会导致以后配置了二级缓存引起数据有效性的问题。

退一步说,即使以后真的调用了按id查询中间表对象的方法,也可以通过调用清除缓存的方法来解决。

4、具体的配置方法

根据我了解的很多hibernate的使用者在调用其相应方法时都迷信的相信“hibernate会自行为我们处理性能的问题”,或者“hibernate会自动为我们的所有操作调用缓存”,实际的情况是hibernate虽然为我们提供了很好的缓存机制和扩展缓存框架的支持,但是必须经过正确的调用其才有可能发挥作用!!所以造成很多使用hibernate的系统的性能问题,实际上并不是hibernate不行或者不好,而是因为使用者没有正确的了解其使用方法造成的。相反,如果配置得当hibernate的性能表现会让你有相当“惊喜的”发现。下面我讲解具体的配置方法.

ibernate提供了二级缓存的接口: 
net.sf.hibernate.cache.Provider, 
同时提供了一个默认的 实现net.sf.hibernate.cache.HashtableCacheProvider, 
也可以配置 其他的实现 比如ehcache,jbosscache等。

具体的配置位置位于hibernate.cfg.xml文件中 
<property name="hibernate.cache.use_query_cache">true</property> 
<property name="hibernate.cache.provider_class">net.sf.hibernate.cache.HashtableCacheProvider</property>

很多的hibernate使用者在 配置到 这一步 就以为 完事了, 
注意:其实光这样配,根本 就没有使用hibernate的二级缓存。同时因为他们在使用hibernate时大多时候是马上关闭session,所以,一级缓存也没有起到任何作用。结果就是没有使用任何缓存,所有的hibernate操作都是直接操作的数据库!!性能可以想见。

正确的办法是除了以上的配置外还应该配置每一个vo对象的具体缓存策略,在影射文件中配置。例如:

<hibernate-mapping> 
<class name="com.sobey.sbm.model.entitySystem.vo.DataTypeVO" table="dcm_datatype"> 
<cache usage="read-write"/> 
<id name="id" column="TYPEID" type="java.lang.Long"> 
<generator class="sequence"/> 
</id>

<property name="name" column="NAME" type="java.lang.String"/> 
<property name="dbType" column="DBTYPE" type="java.lang.String"/> 
</class> 
</hibernate-mapping>

关键就是这个<cache usage="read-write"/>,其有几个选择 
read-only,read-write,transactional,等 
然后在执行查询时 注意了 ,如果是条件查询,或者返回所有结果的查询,此时session.find()方法 不会获取缓存中的数据。只有调用query.iterate()方法时才会调缓存的数据。

同时 get 和 load方法 是都会查询缓存中的数据 .

对于不同的缓存框架具体的配置方法会有不同,但是大体是以上的配置

(另外,对于支持事务型,以及支持集群的环境的配置我会争取在后续的文章中中 发表出来)

3.     总结

总之是根据不同的业务情况和项目情况对hibernate进行有效的配置和正确的使用,扬长避短。不存在适合于任何情况的一个“万能”的方案。

以上结论及建议均建立在自己在对 Hibernate 2.1.2中的测试结果以及以前的项目经验的基础上。如有谬处,请打家提出指正:)!

最后,祝大家 新年快乐!!在新的一年里 取得人生的进步!!!

(另,如有转贴请注明原文链接,谢谢:))

关于hibernate的缓存使用(转)的更多相关文章

  1. hibernate笔记--缓存机制之 二级缓存(sessionFactory)和查询缓存

    二级缓存(sessionFactory): Hibernate的二级缓存由SessionFactory对象管理,是应用级别的缓存.它可以缓存整个应用的持久化对象,所以又称为“SessionFactor ...

  2. Hibernate ——二级缓存

    一.Hibernate 二级缓存 1.Hibernate 二级缓存是 SessionFactory 级别的缓存. 2.二级缓存分为两类: (1)Hibernate内置二级缓存 (2)外置缓存,可配置的 ...

  3. hibernate一级缓存

    理解 Hibernate 一级缓存 Hibernate 一级缓存默认是打开,不需要任何的配置.实际上,你无法强制禁止它的使用. 如果你理解了一级缓存实际上和会话是关联的,就很容易理解一级缓存.总所周知 ...

  4. paip. 提升性能---hibernate的缓存使用 总结

    paip. 提升性能---hibernate的缓存使用 总结 作者Attilax  艾龙,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blog ...

  5. 配置Hibernate二级缓存时,不能初始化RegionFactory的解决办法

    配置Hibernate 二级缓存时,出现以下bug提示: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder&quo ...

  6. Hibernate 所有缓存机制详解

    hibernate提供的一级缓存 hibernate是一个线程对应一个session,一个线程可以看成一个用户.也就是说session级缓存(一级缓存)只能给一个线程用,别的线程用不了,一级缓存就是和 ...

  7. [转] 关于hibernate的缓存使用

    http://blog.csdn.net/woshichenxu/article/details/586361 1.     关于hibernate缓存的问题: 1.1.1.         基本的缓 ...

  8. Hibernate的缓存技术详解

    转载注明出处:http://www.cnblogs.com/xiaoming0601/p/5882980.html 一.什么是缓存: 并不是指计算机的内存或者CPU的一二级缓存:缓存是指为了降低应用程 ...

  9. 记录Hibernate的缓存知识

    一.Hibernate缓存的作用 Hibernate是一个持久层框架,Hibernate要经常访问物理数据库.为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能,Hibernate的缓 ...

  10. Spring控制Hibernate的缓存机制ehcache

    首先在spring.xml中进入bean <prop key="hibernate.cache.use_second_level_cache">true</pro ...

随机推荐

  1. Java下一个简单的数据库分库帮助类

    简介    前面两篇文章主要讲了数据库读写分离和分表分库的一些问题,这篇文章主要讲一下我个人实现的一个分表分库项目.     在此之前,我有写过一个.Net的分库,最近在做Java的项目,就顺便做出一 ...

  2. 用javascript实现java的Map

    function Map(){ var obj={}; //空的容器 //put方法 this.put=function(key,value){ obj[key]=value; //把键值绑定到obj ...

  3. 蜘蛛大战之 站点LOGO(SEO)

    起因: 同事让我看 搜公司名称,百度第一位并没有出现公司网址,是别人的,然后我 惊奇的发现,站点logo 竟然 抓了张 无关紧要的图片,从此 变开始了 为期 10天+的战争: 经过: [2017-06 ...

  4. CYQ.Data V5 分布式自动化缓存设计介绍(二)

    前言: 最近一段时间,开始了<IT连>创业,所以精力和写的文章多数是在分享创业的过程. 而关于本人三大框架CYQ.Data.Aries.Taurus.MVC的相关文章,基本都很少写了. 但 ...

  5. Python的多线程编程

    提到多线程,很多人就会望而却步,本文将由浅入深地带你攻克python多线程编程,并防止你跳入深坑, 首先看一段简单的代码: from time import ctime,sleep def play_ ...

  6. 探索Windows命令行系列(3):命令行脚本基础

    1.实用功能 1.1.为脚本添加注释 1.2.控制命令的回显 1.3.使用数学表达式 1.4.向脚本传递参数 2.使用变量 2.1.变量的命名及定义 2.2.调用变量 2.3.变量的作用域 3.结构语 ...

  7. 小程序之发起请求 wx.request(object)的坑

    这是官方的API,然后官方的实例中 wx.request({ url: 'test.php', //仅为示例,并非真实的接口地址 data: { x: '' , y: '' }, header: { ...

  8. 如何在非 React 项目中使用 Redux

    本文作者:胡子大哈 原文链接:https://scriptoj.com/topic/178/如何在非-react-项目中使用-redux 转载请注明出处,保留原文链接和作者信息. 目录 1.前言 2. ...

  9. php中比较两个变量是否相等的最高效写法

    <?php //php中比较两个变量是否相等的最高效写法 function isEqual($a,$b){ return $a==$b; } var_dump(isEqual(3,3));//t ...

  10. 【Android Developers Training】 103. 查询当前地点

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...