Hibernate 中对象 set 属性时自动保存入库的问题

背景

在某个项目中,通过 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 查出某个对象后,就进入了托管状态,此时对对象的任何属性改动,都会自动保存到数据库中。

解决方法

  1. 通过 new 一个新的对象出来进行操作,这个新的对象是瞬时状态,不会自动保存。
// 查出对象
User user = userManager.findOne(1);
// new 一个新的对象
User newUser = new User();
// 将需要用到的属性赋予新的对象,对于前端显示
newUser.setAge(user.getAge());
newUser.setName("user2");
// 不要对 newUser 进行保存即可。也不要改变 user 的属性
  1. 在 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 一个新的对象来进行操作,或者将对象改成游离态。

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
当使用Hibernate框架,向数据插入一个实体类,如果该实体类有一些属性的值为null,那么在保存就会报错。通常出现这种情况是因为在实体类没有正确地设置属性的值导致的。 要解决这个问题,首先需要确定哪些属性的值是null。可以在将实体类保存到数据库之前,对实体类的属性进行逐个检查,确保每个属性都有正确的值。 如果你使用的是Java 8及以上版本,可以使用Optional类型来避免空指针异常。例如,假设你有一个名为user的实体类,其有一个名为name的属性: ```java public class User { private String name; // ... } // 在保存之前,可以使用Optional类型确保name不为null User user = new User(); Optional<String> nameOpt = Optional.ofNullable(user.getName()); if (nameOpt.isPresent()) { // name不为null,可以进行保存操作 } else { // name为null,需要进行处理 } ``` 如果你使用的是Java 7或以下版本,可以使用if语句来判断属性是否为null。例如: ```java public class User { private String name; // ... } // 在保存之前,使用if语句确保name不为null User user = new User(); if (user.getName() != null) { // name不为null,可以进行保存操作 } else { // name为null,需要进行处理 } ``` 在确定每个属性的值不为null后,就可以将实体类保存到数据了。如果仍然出现保存报错的情况,那么可以考虑检查Hibernate的配置文件,确保数据库连接等配置正确。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值