`
wanglihu
  • 浏览: 919486 次
  • 性别: Icon_minigender_1
  • 来自: 黑龙江
社区版块
存档分类

不要依赖hibernate的二级缓存

阅读更多
一、hibernate的二级缓存
如果开启了二级缓存,hibernate在执行任何一次查询的之后,都会把得到的结果集放到缓存中,缓存结构可以看作是一个hash table,key是数据库记录的id,value是id对应的pojo对象。当用户根据id查询对象的时候(load、iterator方法),会首先在缓存中查找,如果没有找到再发起数据库查询。但是如果使用hql发起查询(find, query方法)则不会利用二级缓存,而是直接从数据库获得数据,但是它会把得到的数据放到二级缓存备用。也就是说,基于hql的查询,对二级缓存是只写不读的。
针对二级缓存的工作原理,采用iterator取代list来提高二级缓存命中率的想法是不可行的。Iterator的工作方式是根据检索条件从数据库中选取所有目标数据的id,然后用这些id一个一个的到二级缓存里面做检索,如果找到就直接加载,找不到就向数据库做查询。因此假如iterator检索100条数据的话,最好情况是100%全部命中,最坏情况是0%命中,执行101条sql把所有数据选出来。而list虽然不利用缓存,但是它只会发起1条sql取得所有数据。在合理利用分页查询的情况下,list整体效率高于iterator。
二级缓存的失效机制由hibernate控制,当某条数据被修改之后,hibernate会根据它的id去做缓存失效操作。基于此机制,如果数据表不是被hibernate独占(比如同时使用JDBC或者ado等),那么二级缓存无法得到有效控制。
由于hibernate的缓存接口很灵活,cache provider可以方便的切换,因此支持cluster环境不是大问题,通过使用swarmcache、jboss cache等支持分布式的缓存方案,可以实现。但是问题在于:
1、 分布式缓存本身成本偏高(比如使用同步复制模式的jboss cache)
2、 分布式环境通常对事务控制有较高要求,而目前的开源缓存方案对事务缓存(transaction cache)支持得不够好。当jta事务发生会滚,缓存的最后更新结果很难预料。这一点会带来很大的部署成本,甚至得不偿失。
结论:不应把hibernate二级缓存作为优化的主要手段,一般情况下建议不要使用。
原因如下:
1、 由于hibernate批量操作的性能不如sql,而且为了兼容1.0的dao类,所以项目中有保留了sql操作。哪些数据表是单纯被hibernate独占无法统计,而且随着将来业务的发展可能会有很大变数。因此不宜采用二级缓存。
2、 针对系统业务来说,基于id检索的二级缓存命中率极为有限,hql被大量采用,二级缓存对性能的提升很有限。
3、 hibernate 3.0在做批量修改、批量更新的时候,是不会同步更新二级缓存的,该问题在hibernate 3.2中是否仍然存在尚不确定。
二、hibernate的查询缓存
查询缓存的实现机制与二级缓存基本一致,最大的差异在于放入缓存中的key是查询的语句,value是查询之后得到的结果集的id列表。表面看来这样的方案似乎能解决hql利用缓存的问题,但是需要注意的是,构成key的是:hql生成的sql、sql的参数、排序、分页信息等。也就是说如果你的hql有小小的差异,比如第一条hql取1-50条数据,第二条hql取20-60条数据,那么hibernate会认为这是两个完全不同的key,无法重复利用缓存。因此利用率也不高。
另外一个需要注意的问题是,查询缓存和二级缓存是有关联关系的,他们不是完全独立的两套东西。假如一个查询条件hql_1,第一次被执行的时候,它会从数据库取得数据,然后把查询条件作为key,把返回数据的所有id列表作为value(请注意仅仅是id)放到查询缓存中,同时整个结果集放到class缓存(也就是二级缓存),key是id,value是pojo对象。当你再次执行hql_1,它会从缓存中得到id列表,然后根据这些列表一个一个的到class缓存里面去找pojo对象,如果找不到就向数据库发起查询。也就是说,如果二级缓存配置了超时时间(或者发呆时间),就有可能出现查询缓存命中了,获得了id列表,但是class里面相应的pojo已经因为超时(或发呆)被失效,hibernate就会根据id清单,一个一个的去向数据库查询,有多少个id,就执行多少个sql。该情况将导致性能下降严重。
查询缓存的失效机制也由hibernate控制,数据进入缓存时会有一个timestamp,它和数据表的timestamp对应。当hibernate环境内发生save、update等操作时,会更新被操作数据表的timestamp。用户在获取缓存的时候,一旦命中就会检查它的timestamp是否和数据表的timestamp匹配,如果不,缓存会被失效。因此查询缓存的失效控制是以数据表为粒度的,只要数据表中任何一条记录发生一点修改,整个表相关的所有查询缓存就都无效了。因此查询缓存的命中率可能会很低。
结论:不应把hibernate二级缓存作为优化的主要手段,一般情况下建议不要使用。
原因如下:
1、 项目上层业务中检索条件都比较复杂,尤其是涉及多表操作的地方。很少出现重复执行一个排序、分页、参数一致的查询,因此命中率很难提高。
2、 查询缓存必须配合二级缓存一起使用,否则极易出现1+N的情况,否则性能不升反降
3、 使用查询缓存必须在执行查询之前显示调用Query.setCacheable(true)才能激活缓存,这势必会对已有的hibernate封装类带来问题。
总结
详细分析hibernate的二级缓存和查询缓存之后,在底层使用通用缓存方案的想法基本上是不可取的。比较好的做法是在高层次中(业务逻辑层面),针对具体的业务逻辑状况手动使用数据缓存,不仅可以完全控制缓存的生命周期,还可以针对业务具体调整缓存方案提交命中率。Cluster中的缓存同步可以完全交给缓存本身的同步机制来完成。比如开源缓存swarmcache采用invalidate的机制,可以根据用户指定的策略,在需要的时候向网络中的其他swarmcache节点发送失效消息,建议采用。
分享到:
评论

相关推荐

    hibernate二级缓存实例

    在这个"hibernate二级缓存实例"中,我们将深入探讨二级缓存的原理、配置以及在实际项目中的应用。 首先,我们需要了解一级缓存和二级缓存的区别。一级缓存是Session级别的,每个Session都有自己的一级缓存,用于...

    Hibernate二级缓存

    Hibernate二级缓存是一种提高应用程序性能的技术,它将数据存储在SessionFactory级别的缓存中,使得数据可以在不同的Session之间共享。这与一级缓存(Session级别)不同,一级缓存仅存在于单个Session生命周期内,当...

    hibernate一级缓存、二级缓存和查询缓存

    **hibernate一级缓存、二级缓存和查询缓存** 在Java的持久化框架Hibernate中,缓存机制是提高应用程序性能的关键要素。缓存能够减少数据库的访问次数,提高数据读取速度,并且在一定程度上降低了系统的负载。本文将...

    hibernate二级缓存示例源码

    **hibernate二级缓存详解** Hibernate作为Java领域中广泛使用的对象关系映射(ORM)框架,极大地简化了数据库操作。然而,在处理大量数据时,性能优化显得尤为重要,这就是二级缓存的作用。本文将深入探讨Hibernate...

    hibernate二级缓存java包下载

    在博客中,可能涉及了如何配置 Hibernate 二级缓存的具体步骤,包括添加依赖、配置缓存提供者、调整 Hibernate 配置文件以及实体类的缓存注解等。通过学习这些内容,开发者可以更好地理解并掌握如何在实际项目中有效...

    springboot+jpa(hibernate配置redis为二级缓存) springboot2.1.4

    通过以上步骤,我们就成功地在Spring Boot 2.1.4.RELEASE项目中配置了使用Redis作为Hibernate二级缓存的环境。这将显著提升数据库查询效率,减少对数据库的压力,尤其在高并发场景下,效果尤为明显。记得在实际生产...

    Spring集成的Hibernate配置二级缓存

    以EhCache为例,我们需要在项目中引入ehcache-core或ehcache的依赖,并在Hibernate配置文件(hibernate.cfg.xml或persistence.xml)中启用二级缓存,添加如下配置: ```xml <property name="hibernate.cache.use_...

    为Spring集成的Hibernate配置二级缓存

    2. **配置Hibernate**:在Hibernate的配置文件`hibernate.cfg.xml`中启用二级缓存并指定缓存提供商。以下是一个使用Ehcache的示例: ```xml <property name="hibernate.cache.use_second_level_cache">true ...

    hibernate 二级缓存

    本篇文章将深入探讨Hibernate二级缓存的概念、工作原理以及如何在实际项目中设置和使用。 **一、二级缓存概念** 一级缓存是每个Hibernate Session内部的一个内存区域,用于存储Session期间的操作对象。当Session...

    hibernate二级缓存(包括注解方式)

    标题“hibernate二级缓存(包括注解方式)”指出了本文将探讨的是Hibernate框架中的二级缓存机制,并且会涉及使用注解的方式进行配置。Hibernate是一个流行的对象关系映射(ORM)框架,它允许开发者在Java应用中使用...

    Hibernate4二级缓存实例(源码)

    这里它被用作Hibernate二级缓存的实现方式,这意味着当数据首次从数据库中读取后,会被存储在memcached中,后续请求可以直接从缓存中获取,避免了频繁的数据库交互,从而提高了系统的响应速度。 **知识点详解:** ...

    hibernate二级缓存要导入的包

    本压缩包提供的资源应该包含了实现Hibernate二级缓存所需的关键组件和库文件。 一级缓存是Hibernate Session内的缓存,它是每个Session实例独有的,当Session关闭时,一级缓存中的数据也会被清除。而二级缓存则是一...

    hibernate二级缓存 SSH

    在这个项目中,"hibernate二级缓存 SSH" 的标题表明我们将探讨如何在SSH框架中实现Hibernate的二级缓存功能。Hibernate二级缓存是一个优化策略,它能提高数据访问性能,减少对数据库的直接访问。 首先,Struts2作为...

    hibernate二级缓存

    Hibernate 二级缓存是 ORM 框架 Hibernate 中的一个重要特性,它旨在提高应用程序的性能和数据一致性。二级缓存允许对象在多个会话之间共享,从而减少了对数据库的访问次数,降低了系统的 I/O 负担。在这个主题中,...

    hibernate5.1二级缓存包

    1. **引入依赖**:首先需要在项目的 Maven 或者 Gradle 构建文件中添加相应的二级缓存库依赖,如 Ehcache 或 Infinispan。 2. **配置**:在 Hibernate 的配置文件(如 hibernate.cfg.xml)中启用二级缓存,并指定...

    Hibernate二级缓存+分页功能

    **一、Hibernate二级缓存** Hibernate一级缓存是指Session级别的缓存,它是默认开启的,每个Session都会维护一个对象缓存,用来存放该Session加载的实体对象。一级缓存的生命周期与Session相同,当Session关闭时,...

    hibernate的一级缓存和二级缓存

    《深入理解Hibernate的一级缓存与二级缓存》 Hibernate作为一款强大的ORM框架,其缓存机制是优化数据库操作性能的关键之一。缓存主要分为一级缓存和二级缓存,它们各自承担着不同的职责,共同提升了数据访问的效率...

    Hibernate二级缓存实例带jar包

    在Java的持久化框架Hibernate中,二级缓存是一个重要的性能优化工具。它允许应用程序存储已经查询过的数据,以便后续请求可以快速获取,而无需再次访问数据库。本实例着重讲解如何在Hibernate项目中配置和使用二级...

Global site tag (gtag.js) - Google Analytics