`
raymond2006k
  • 浏览: 290900 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Hibernate查询缓存的一个可靠性问题

阅读更多
  之前在对项目中Hibernate的缓存性能进行测试时发现的一个问题,不知大家有没有遇到或者是解决办法。
    问题是:使用sql query且是多表关联查询,并启用查询缓存时,对关联表修改后,查询缓存未能更新,出现了不正确的查询结果集。

    测试场景:
    1. 用例:为简单起见,测试中使用了两表关联查询。查询指定角色 (roleCode) 的所有已授权限点 (Perm集合)
    2. 库表:
          权限点表(sys_perm )字段: permCode, permName, moduleCode,...
         角色授权表(sys_role_perm )字段: roleCode, permCode, createTime,...

   3. 关联查询
(其实仅判断所授权限点编码集合,用Hibernate 关联抓取,就可以解决,并且二级缓存也能很好的控制此问题;即使用 named sql query进行鉴权,也只需查 sys_role_perm表返回 permCode集合。这里返回 perm 集合, 这里主要是为测试关联查询时的cache query问题而举的一个例子)
<!-- 角色拥有的所有已授权限集合 -->
<sql-query name="system.roleperms">
	select  *  from sys_perm t join sys_role_perm o 
    on t.perm_code = o.perm_code 
    where o.role_code = :roleCode 
</sql-query>
</class>

   
    3. 预置数据:
         角色编码: STESTOR,
         权限点:permCode 组织新增: ORG_ADD
         在 sys_role_perm 表中为 STESTOR 授予 组织管理新增的权限:
        (STESTOR,ORG_ADD,2007-3-27 10:34:32)

    4. 测试代码:
     执行三次doQueryRolePerms 查询功能,在第二次执行完毕时,删除 (STESTOR,ORG_ADD) 这条授权,观察第三次查询是否重新去数据库取数。

for (int i = 0; i < 3; i++) {
   System.out.println(" Execute No. " + i + " ********************");
   List perms = (List)perm.doQueryRolePerms("STESTOR"); 		
   System.out.println("(" + i +")result size:"  + perms.size()  );

   if(i % 2 == 1) 
    rolePerm.doRemoveByVO(rolePermVO1); //删除授权:STESTOR, ORG_ADD	
}

   
   5. 执行分析:
       第1,2次执行,由于有预置授权,因此 result size: 1;
       第3次执行查询,由于删除了唯一的授权,那么 result size: 0。

    6. 实际结果:
       

 Execute No. 0 ********************
2008-10-06 17:26:26,406 [DEBUG](AbstractBatcher.java,324) - select  this.PERMCODE as  PERM1_0_,  this.MODULECODE as  MODULE2_15_0_,  this.PERMTYPECODE as  PERM3_15_0_,  this.PERMNAME as  PERM4_15_0_,  this.PERMDESC as  PERM5_15_0_,  this.PORTNO as  PORT6_15_0_ from (select  t.perm_code as permCode, 
       t.module_code as moduleCode, 
       t.perm_name as permName, 
       t.perm_desc as permDesc, 
       t.port_no as portNo, 
       t.perm_type_code as permTypeCode 
  		from sys_perm t join sys_role_perm o 
    on t.perm_code = o.perm_code 
    where o.role_code = ? ) this  
(No.0)result size:1

 Execute No. 1 ********************
(No.1)result size:1
2008-10-06 17:26:26,484 [DEBUG](AbstractBatcher.java,324) - delete from SYS_ROLE_PERM where PERM_CODE=? and ROLE_CODE=?

 Execute No. 2 ********************
(No.2)result size:1

Time: 0.422

OK (1 test)
       


      从结果可以看出,第1次,执行了查询;
       第2次没有执行查询,说明 query cache,二级cache都起了作用。
       但第3次查询,没有重新执行sql,仍然返回的是第二缓存的结果。
       因此可以判定, 第3次查出的是旧数据。

     7. 分析及结论:
      Hibernate query cache 在关联表的数据删除时,没能通知查询缓存及时失效或更新, 以便获取最新数据。

     8. 解决办法
     暂时还没找到Hibernate自身的解决办法, 为避免此问题,可以关闭查询缓存。 看大家有没有遇到过此问题,分享下你们的经验。

     如果hibernate真的没有解决这个问题,我能想到的一个思路就是,在 named query执行时,分析出查询的关联表,并在关联表进行 create,update,delete时及时通知该 named query的缓存失效。
     关联查询,特别是多表关联,且操作复杂时,要精细的进行缓存通知比较困难(例如:修改了 Admin 角色的授权,就对上例的查询没有影响,而修改了 STESTOR 角色的授权才需要通知cache更新,但这判断起来有一定难度),可以做一个笼统的逻辑,即 create,update,delete 关联表后,对 named query的cache都要通知它清除,以便重新查询获取最新数据。

      query cache的利用率,即命中率取决于具体业务的增删改操作的频率,这个测试暂不考虑此因素 query cache的价值问题。


   经过一天的努力,终于解决此问题, 并附源代码和fix包: 解决Hibernate SQL Query Cache的一个可靠性问题(附源码)
分享到:
评论
7 楼 QuakeWang 2008-10-08  
不错,可以提交bug fix给hibernate团队
6 楼 raymond2006k 2008-10-08  
经过一天的努力,终于解决此问题。 具体分析和修正方法见下篇 blog 并附源代码和fix包: 解决Hibernate SQL Query Cache的一个可靠性问题(附源码)
5 楼 raymond2006k 2008-10-07  
不过时间没白费, 走了一下源码,大致找到了问题所在,  SQLQueryReturnProcessor在分析 query时,用于判断缓存失效的  querySpaces[]只分析出了返回结果对应的表,例如例子中的权限点表:sys_perm,  而sql中的关联表没有分析出来,并放到 querySpaces[] 中。

明天争取能通过修改源码解决此问题。:)
落班,收工。
4 楼 raymond2006k 2008-10-07  
主要是一些复杂的查询,比如多表关联(3表,5表等), 无VO对应结果集查询等。
这样选型有我们的考虑, 一两句话也说不完,我另一片帖子比较详细的说了为什么用 sql query的问题。

这个不是重点啦,项目都完工了。 高手,你就当发现了 hibernate 使用时的问题,正在找解决办法,:)  。

下午抽空用 hibernate3.3.0 GA , 3.3.1 GA 测试了一下,依然有此问题。
3 楼 QuakeWang 2008-10-07  
raymond2006k 写道

主要是我们项目处于项目特点的考虑,主要使用的是 named sql query。

很好奇你的项目有什么特殊地方,需要大量使用native sql query?
hibernate提供native sql query目的是为了在极少场景下能够使用一些数据库的特性,比如说oracle的connect查询。从你前面的例子看,用普通的hsql比native sql要简单许多,也看不出来有地方需要用到数据库的特殊sql语句。
2 楼 raymond2006k 2008-10-07  
回楼上,hql的缓存可靠性虽然没实测,但根据hibernate 处理hql的内在机制,和你们的经验,相应肯定是没问题的, 因为hibernate很容易在解析 hql 时判断出关联表。

主要是我们项目处于项目特点的考虑,主要使用的是 named sql query。
在浏览hibernate源码时,某一天突然对 hibernate 能否很好的处理 sql  方式下的query cache可靠性产生了一点好奇, 然后就进行了测试。 本来期待它应该很好的处理了这个问题,但测试结果也出乎我的意料。  估计Gavin King 老人家漏了这一环,呵呵。

firebody 那篇帖子很受用,呵呵,多谢了。 我也的再详细读读源码了,看能否找出敏捷的解决办法;或者看看新版本有没有解决此问题。
1 楼 QuakeWang 2008-10-06  
注意到你这里使用的是sql-query,可能hibernate的cache清除机制对sql-query没有处理,我在以往的项目中使用query cache都是hsql,实践证明是很可靠的,你可以将sql-query改成hsql试试看。

另外推荐这篇分析hibernate query cache原理的文章:
http://www.iteye.com/topic/10537

相关推荐

    库提供工具,用于检测N +1查询并计算使用Spring和Hibernate生成的查询(高分毕设).zip

    1. Spring框架:Spring是一个轻量级的Java开发框架,提供了丰富的功能和模块,用于开发企业级应用。它包括IoC(Inverse of Control,控制反转)容器、AOP(Aspect-Oriented Programming,面向切面编程)等特性,可以...

    学习J2EE ( spring、springmvc、mybatis、hibernate )

    1. Spring框架:Spring是一个轻量级的Java开发框架,提供了丰富的功能和模块,用于开发企业级应用。它包括IoC(Inverse of Control,控制反转)容器、AOP(Aspect-Oriented Programming,面向切面编程)等特性,可以...

    基于struts+hibernate+spring+easyui+mysql的网上商城项目实战源码.zip

    自1998年首次发布以来,MySQL以其卓越的性能、可靠性和可扩展性,成为全球范围内Web应用程序、企业级解决方案以及其他各种数据处理场景的首选数据库平台之一。 以下是对MySQL数据库的详细介绍: 核心特性与优势 ...

    Web开发工具和方法课程的学术项目Java、Spring、Hibernate、Angular

    1. Spring框架:Spring是一个轻量级的Java开发框架,提供了丰富的功能和模块,用于开发企业级应用。它包括IoC(Inverse of Control,控制反转)容器、AOP(Aspect-Oriented Programming,面向切面编程)等特性,可以...

    java开源包1

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    java开源包11

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    java开源包2

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    java开源包3

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    java开源包6

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    java开源包5

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    java开源包10

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    java开源包4

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    java开源包8

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    java开源包7

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    java开源包9

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    java开源包101

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    Java资源包01

    Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。 彩信发送开发包 apimms apimms 提供了各种语言用来发送彩信...

    MF00001-JAVA多用户B2B2C商城源码.zip

    JAVA多用户B2B2C商城系统源码 开发语言 : JAVA ...系统支持多服务器分布式部署,互通机制,也可以修改系统相关功能进行session缓存共享处理,轻松完成分布式部署,为大数据、大访问量的运营商提供可靠的功能保证。

    J2EE系统设计方案(1).doc

    J2EE体系结构提供中间层集成框架用来满足无需太多费用而又需要高可用性、高可靠性 以及可扩展性的应用的需求。通过提供统一的开发平台,J2EE降低了开发多层应用的费 用和复杂性,同时提供对现有应用程序集成强有力...

    J2EE系统设计方案.doc

    J2EE体系结构提供中间层集成框架用来满足无需太多费用而又需要高可用性、高可靠性 以及可扩展性的应用的需求。通过提供统一的开发平台,J2EE降低了开发多层应用的费 用和复杂性,同时提供对现有应用程序集成强有力...

Global site tag (gtag.js) - Google Analytics