同事总结的hibernate意料外更新数据酷问题。
致action开发人员:
由于前些日子发现,从数据库中取出的Bean,被修改后,其修改的结果会重新反映到数据库中,提出下面分析和解决方法。
原因:
正常情况下,Service结束后,事务也就结束了。这个时候Hibernate Session就应该消失,但是,由于数据提供延迟加载
的技术支持,所以需要在Web层提供Session,用于对数据进行加载,这个时候就需要对Session的生命周期进行延长。Spring
提供了OpenSessionInViewFilter类,当一个web请求进入的时候,该请求就被分配了一个Hibernate Session到该请求的线程
上,直到该请求结束,这个时候我们通过Manager从数据库中检索一条信息到Controller层,无论在Controller层如何修改,
都不会同步到数据库中的,因为默认Session的刷新方式是AUTO(重新检索数据,提交事务,刷新数据会激活数据同步功能),
但是,通常情况下,我们对在修改后,又使用其他Manager方法对同一个Session进行了激活,使得激活了Session中的刷新事件,
这样的后果就是Hibernate把已经修改的数据作为合法的脏数据进行提交了。使得数据库中的值进行了修改。也就是说数据库
中的数据被修改了。是因为大家在同一个请求中使用了多次manager中的方法,其在最后一次使用manager方法之前,Bean中的
数据Bean进行了修改。
解决方法:
由于该Bean在hiberante中管理,如果瞬时化,会导致hiberante缓存中没有该数据,会重数据库中再次检索,这样即使我们
修改了也无济于事,所以现在提出一下解决方法。
YHB.DISABLE_SYNC(YHB中的一个常量),标记一个对象禁止与数据库中的对象同步。
当我们重数据库中检索一条信息,处于某种原因对该对象中的数据进行了修改,又不想同步到数据库中,请执行该对象的
Bean.setVersion(YHB.DISABLE_SYNC),就可以禁止该对象对数据库的修改,该方式只对自动提交更新有用,手动调用update方式无效,
后台使用该方式后还执意调用update对象,会导致版本不同步异常发生。该方式作用的对象只对不想更新的Sesstion中持久化对象
有作用,请大家确认是否必要使用。
例:
UkeMember member = manager.findById(1); // 获取一个会员
Integer version = member.getVersion(); // 暂存会员对象的版本号,
// 如果是前台没有版本号的概念,可以忽略
member.setVersion(YHB.DISABLE_SYNC); // 禁止该对象内容与数据库对象同步
member.setName("hello"); // 修改该对象中的内容
promotionRuleMng.initPromotionRules(member); // session再次激活,该对象存活去session中。
// 数据被同步到数据库中就是它照成的。
member.setVersion(version); // 还原原来的版本号
Assert.assertTrue("liutie".equals(name)); // 验证或者返回
以上功能已经实现,请大家注意更新。