遇到这个问题了
背景
在某个项目中,通过 Heibernate 查出某个对象后,对属性进行了 set 操作,并没有进行 update 操作,但是在数据中自动保存了。
显然这并不是我想要的,我只是想 set 一下属性,在前端显示,并不想入库,但是 Heibernate 自动保存了。
// 查出对象,原来的 name 为 user1 User user = userManager.findOne(1); // 将userName 设置为 user2 ,用于前端显示,并没有保存 user.setName("user2"); // heibernate 自动进行了保存,库中的 name 为 user2
原因
Heibernate 中对象分为以下几种状态:
瞬时状态:
实际上就是 new 了一个普通的 JavaBean 对象。
托管状态:
当瞬时对象调用了管理器的 persist() 后,即可将一般的 JavaBean 做为了持久 Bean,该 Bean 的任何属性改动都会牵涉到数据库记录的改动。
一旦该记录 flush 到数据库之后,并且事务提交了,那么此对象不在持久化上下文中,即:变为了游离(没人管的孩子)状态了。在游离状态的时候调用更新、刷新方法后,游离状态对象就变为了在持久化上下文的托管状态了。
通过管理器的 find 方法,将实体从数据库查询出来后,该实体也就变为了托管形态。
持久化状态:
当处在托管状态的实体 Bean 被管理器 flush 了,那么就在极短暂的时间进入了持久化状态,事务提交之后,立刻变为了游离状态。您可以把持久化状态当做实实在在的数据库记录。
游离状态:
游离状态就是提交到数据库后,事务 commit 后实体的状态,因为事务已经提交了,此时实体的属性任你如何改变,也不会同步到数据库,因为游离是没人管的孩子,不在持久化上下文中。
销毁对象:
一般要删除一个持久化对象的时候都是先 find 出来,之后调用 remove 方法删之,此时这个对象就是销毁对象,实际上就是瞬时对象的另一种形态罢了。
根据上面的各种状态,可以得知。通过 find 查出某个对象后,就进入了托管状态,此时对对象的任何属性改动,都会自动保存到数据库中。
解决方法
通过 new 一个新的对象出来进行操作,这个新的对象是瞬时状态,不会自动保存。
在 find 查出的对象 set 属性前,将其状态改为游离状态。这样的话会用到 session 的几个方法:close、clear、evict。
close 方法:关闭 session 这样这个对象肯定是游离态了,因为 session 已经关闭了,但是往往我们实际的开发过程中,session 在后面是要用的到的,所以这个方法可行,但是不一定用得上,分清具体的情况。
clear 方法:将 session 中的所有的对象全部清除出缓存,这个方式有点劳师动众,不过 session 清除了全部的对象之后自然就会变为游离态了,这样做不是很好吧我感觉。
evict 方法:将某一个对象清除出缓存 session,这个方法是很好的实现方式,推荐使用。调用的时候是这样的,session.evict(Object obj) 这样就可以了。
这边推荐使用 evict 方法,代码如下:
@PersistenceContext private EntityManager entityManager; ...... // 获取 session HibernateEntityManager hEntityManager = (HibernateEntityManager)entityManager; Session session = hEntityManager.getSession(); // 查出对象,原来的 name 为 user1 User user = userManager.findOne(1); // 将对象清除出缓存 session,这样后面对属性的改变就不会自动保存 session.evict(user); // 将userName 设置为 user2 ,用于前端显示 user.setName("user2"); // 由于清除出了 session,heibernate 不会对这个对象进行保存,库中的 name 仍为 user1
总结
通过 Hibernate 查询出来的对象,改变其属性后,Hibernate 会对其自动保存入库。
如果不需要使用这个功能,可以通过 new 一个新的对象来进行操作,或者将对象改成游离态。
———————
作者:yujunyi_
来源:CSDN
原文:https://blog.csdn.net/qqfo24/article/details/83275610
版权声明:本文为博主原创文章,转载请附上博文链接!