今天测试的同事在页面上测试的时候,发现一个神奇的bug。当你去查询调用一个JPA语句的时候,他会自动update这条记录。根据业务要求,页面的数据需要通过主表对象来显示,当需要显示主表数据时,先查询字表数据,再把查询到的字表数据赋值给主表,将主表对象用于页面显示,代码执行完毕后,发现数据库字表数据覆盖了主表数据,很纳闷,查看代码,在把子表数据赋值给主表对象后,我仔细回想代码里也没有调用update方法啊,我并没有写更新主表对象的代码呀,数据库怎么会被更新?
后来查看日志发现,当将正式表数据赋值给临时表时,有一条update语句执行了。
查看资料后才知道,使用JPA查询后的对象处于持久态,持久态的对象属性在被set后,会自动执行update语句更新数据库。
这就要说到hibernate对象的三种状态
1、瞬时态:对象刚new出来,还未通过save方法保存到数据库,或通过游离态对象、持久化态对象delete后。(既没有被保存到数据库中,也不处于session缓存中)
2、持久化态:通过从数据库查询出来,或瞬时态对象save保存后,或游离态对象update后)(已经被保存到数据库中同时也处于session缓存中)
3、游离态:通过持久化态对象关闭session,或通过evict、clear方法强制将持久化态对象清理出session。(已经被保存到数据库中但不处于session缓存中)
持久态到游离态的方法有:session.close()、session.evict(obj)、session.clear()
close():关闭session,整个session中的持久态对象都成为游离态
clear():清楚session中的所有缓存,所有持久化对象变为游离态
evict(obj):把某个持久化状态的对象从session中清除,该对象变为游离态
刚用JPA查询出来的数据处于持久化态
根据三个方法的介绍,最好的处理方式应该选择evict(obj)方法。
由于业务需求,我的解决方式是,新建一个临时态的临时表对象,将查询到的正式表对象赋值给临时态对象,这样就不会触发update语句,经测试,问题解决。
出现这种现象的前提,查询以及对查询后的实体set值都必须在一个事务里,并且在方法执行结束,事务提交前,不管有没有显示调用update,JPA都会自动调用update.
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/91014.html