记一次hibernate 的saveOrUpdate方法异常

报错异常如下:

Exception in thread"main"org.hibernate.NonUniqueObjectException: 
a different object with the same identifier value was already exit。

报错原因:
异常解释 :不是唯一对象异常,即hibernate的session中存在不同的但是主键相同的对象。所以在执行session.saveOrUpdate方法时不知道去保存那个对象。
出现概率:我遇到的这个问题,有的时候不会报错,但是绝大部分是会报错的。

解决方案
先上代码,更加直观。

#controller层代码#
@Action("saveUser")
public void saveUser() {
            try {
                  /*名字不能为空**/
                  if (StringUtils.isEmpty(this.user.getUserName())) {
                        Logger.error("userName can not be empty");
                        renderState(false);
                        return;
                  }
                  /*手机号码不能为空*/
                  if (StringUtils.isEmpty(this.user.getMobile())) {
                       Logger.error("mobile can not be empty");
                        renderState(false);
                        return;
                  }
                  if (!MobileUtils.isMobile(this.user.getMobile())) {
                        Logger.error("Wrong format of mobile phone ");
                        renderState(false);
                        return;
                  }
                  User exitUser = channelUserManager.getChannelUser(this.user.getId());
                  if (exitUser.getStatus != 1) { 
                        userManager.saveUser(this.user);
                        renderState(true);
                  }else{
                        renderState("操作失败,该用户状态被禁用");
                  }
            } catch (Exception e) {
                  e.printStackTrace();
            }
            renderState(false);
#service层代码#
 public void saveUser(User user) {
            if (user == null) {
                  return;
            }
            channelUserDao.save(channelUser);
      }
#dao层代码(通用save方法)
 public void save(T data) {
            Assert.notNull(data);
            getSession().saveOrUpdate(data);
      }

上面代码执行saveUser()方法时会报这个错误。它最终调用的是getSession().saveOrUpdate()这个方法。顺便说一下session是hibernate的session,是用来操作数据库的,不是servlet中的session,cookie。

分析:controller层执行保存user这个方法时,他首先接受来自前端编辑后的user对象(new)。根据其id查询出原来的对象(old),判断他的status是否等于1。也许是其他逻辑,反正就是你需要根据主键去查出原来的对象(old),进行一些逻辑判断或者操作,然后再把这个新的对象(new)保存进去。然而你就会发现在session中存在了两个主键相同的对象,第一个对象是查出来的,第二个是你要保存的,由于主键相同,hibernate无法识别保存那个对象,这里应该可以理解为,saveOrUpdate方法是根据主键来更新的,session去执行更新操作时,存在两个主键一样的对象,让它感到矛盾,就抛出了异常。

如何解决:

  • 使用getSession().merge(Object object)
    在dao层做处理,由于上面的那个是通用的,重新写一个save方法。
public void save(User user) {
            Assert.notNull(user);
            Object merge = getSession().merge(user);
            User mergeUser=(User) merge;
            getSession().saveOrUpdate(mergeUser);
      }

getSession().merge方法它会在 session 缓存中找到持久化对象(old),把新对象(new)的属性赋过去,再保存原session中的持久化对象。
merge是合并的意思,将新对象的属性值赋值给之前查出来的那个,再将old保存进去。

  • 这个方法其实和第一个方法的原理相同,
              exitUser.setUserName(this.user.getUserName());
              exit.setStatus(this.user.getStatus());
              exit.setMobile(this.user.getMobile());
              exit.setRemark(thisuser.getRemark());
              userManager.saveUser(exitUser);

这次我保存的还是我查出来的那个对象,但是某些属性值给改成了新对象的值,这样session中就不会有NonUniqueObject异常了。

拓展:
想要真正了解核心,就要了解hibernate对象的三种状态。
可参考博客:https://blog.csdn.net/pangqiandou/article/details/53386589

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值