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。

[b]6. 实际结果:[/b]


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包: [url=http://raymond2006k.iteye.com/blog/250427]解决Hibernate SQL Query Cache的一个可靠性问题(附源码) [/url]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值