托管态update更新异常——a different object with the same identifier value was already associated withthe sess

转载 2015年07月09日 11:32:03
  • 问题:这个著名的托管态update更新异常
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated withthe session

  • 早先的发生场景:
几乎所有搞过OrMapping持久化程序的开发者都多多少少碰到过这个异常.
这个异常通常发生在一个session 内对同一个数据库对象生成了多个(经常是load(id)/get(id)一个,又new+setId(id)一个),然后又对其进行了update()或者save() .
从业务逻辑的角度,经常发生在修改/更新的操作中.

  • 早先的发生原因和解决手段:
经常是session忘记关闭,或忘记commit(),造成本该分为两个session的,合为了一个session,就出现了此异常.
解决手段也很简单,通过session关闭和事务,把相同的操作对象从session级别或者事务级别上分隔开.


  • 现在问题的新变化:
  1. hibernate3.0以后,getCurrentSession()技术的出现,session pool的出现,session不再需要手动open,也不需要手动关闭,反而使问题复杂化
  2. spring TransactionManager的出现,使问题更复杂
      各种Manger Bean, DAO bean里打开了spring事务管理, spring事务又定义了各种操作隔离机制,比如:
       "一个在事务下的方法,调用另一个方法,则另一个方法不再开事务,而是涵盖在调用它的方法的事务之下"
       "一个在事务下的方法,调用另一个方法,另一个方法建立新事务,父方法的事务暂停,待另一个方法执行完毕,才继续事务".

   3. 以struts2 web 框架为代表的一些扩展功能,使问题更复杂
     典型的比如struts2 的domain Model (域模型)传参. JSP直接向Action的实例变量对象的属性赋值.如果实例属性存在就直接setter,如果实例属性不存在就自动new 实例
     如果这个domain Model是一个实体bean,如果你通过JSP页面set了它的id,或者之前就已经将其持久化了,这就更复杂了.

  4. 如spring OpenSessionInViewFilter的出现,用于解决LAZYInitialization延迟加载问题
  把session的周期交给servlet filter来管理,每当有request进来,就打开一个session,response结束之后才关闭它,这样可以让session存在于整个servlet request请求周期中

   还有许多技术,都或多或少的产生的影响,上面的1-4是最典型的.


  •   a different object with the same identifier value was already associated withthe session    问题的解决:
    其实我没有特别好的解决办法,问题本身也是见仁见智的,需要针对不同场景不同业务逻辑随机应变.本文只是探讨性的文章,属于开放性质的.
    从我的经验来说,我倾向于从两方面解决:
    1. session方面
    从程序的角度,多分析问题,找到session的开始和结束点.
    不过说句实话,这真的很难,因为现在的代码越来越框架化,模块化,封装得越来越深,session根本不暴露在业务层之外, 操作经常要上溯到很高层的父类,尤其当和事务挂钩时,更是复杂. 而且现在session的底层操作也越来越晦涩,基于池操作的,基于ThreadLocal操作的,基于JTA的.
    2.从update()方面
    目前比较普遍的观点,用merge()方法解决是一个比较"傻瓜"的解决办法.
    JSR-220里对session.merge()方法的描述:
Copy the state of the given object onto the persistent object with the same identifier.
将给定对象的state(状态,即实例属性)拷贝给到具有相同id的持久化对象
If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance.
如果当前没有持久化对象关联到session,当前对象会被加载为持久化对象,并(在update后)返回持久化对象
If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session.
如果给定实例还没存盘,就存一份copy,并且(这份)copy返回作为新的持久化对象.而给定的对象不会再关联到session
    简单总结:
    merge()会用"拷贝状态copy the state",也就是属性赋值的直接方法,完成相同id对象的更新,实际就是把内容克隆过去.
    如果是一个新的对象实例,merge()实际就等同于save()和persist()
    但与save()和persist()不同,merge()完成后,其操作的对象是托管态.

jpa 实体4个状态

not-null property references a null or transient value: 出错信息是说,一个要求不能为空的属性为空值(null),你仔细检查下保存的数据,里面应...
  • yuwenlanleng
  • yuwenlanleng
  • 2016年09月20日 15:19
  • 1030

2014-J2EE开发工作中遇到的异常问题及解决方法总结

本人做了近三年的J2EE开发工作,主要架构为SSH+MySQL+Tomcat,项目中也用到了一些第三方的开源工具或者中间件,工作中难免会遇到各种各样的异常问题,对于一些给我造成比较大的麻烦的问题,我习...
  • rchm8519
  • rchm8519
  • 2014年11月30日 17:48
  • 24600

hibernate中对象的3种状态 瞬时态、持久态、脱管态

Hibernate的对象有3种状态,分别为:瞬时态(Transient)、 持久态(Persistent)、脱管态(Detached)。处于持久态的对象也称为PO(Persistence Object...
  • jxq0816
  • jxq0816
  • 2014年01月03日 17:02
  • 2610

使用Hibernate操作对象的时候报错【update一个对象报的错】

文章来源:http://blog.163.com/chinagujing@yeah/blog/static/170937439201092405558777/ 昨天在一个方法中update一...
  • buster2014
  • buster2014
  • 2015年08月05日 15:54
  • 1780

brew update 失败结局办法

$ cd `brew --prefix` $ git remote add origin https://github.com/Homebrew/homebrew.git $ git fetch or...
  • chenlei_525
  • chenlei_525
  • 2016年11月11日 12:28
  • 3698

追踪所下载的AssetBundle

Unity will only allow you to have a single instance of a particular AssetBundle loaded at one time i...
  • wangyao1052
  • wangyao1052
  • 2015年06月26日 15:36
  • 581

12c 应答方式安装数据库的一点补充already exists. Specify another SID

今天删除数据库时采用了drop database语句,从新安装时遇到错误:“The Oracle system identifier(SID) "cdb" already exists. Specif...
  • qq_27966627
  • qq_27966627
  • 2016年04月01日 17:36
  • 372

Unity5.0更新列表

Unity 5.0 is our biggest and boldest release ever. Powerful new features in Unity 5 include: The ...
  • fanglrui
  • fanglrui
  • 2015年04月29日 20:27
  • 1791

swit3.1 (9)笔记 内存管理和方法

Transitioning to ARC Release Notes(oc内存管理) https://developer.apple.com/library/content/releasenot...
  • u014544346
  • u014544346
  • 2017年04月22日 18:16
  • 244

Git 配置仓库链接 和一些冲突解决

首先        下载 安装GIT 官网下载页面:  http://git-scm.com/downloads      WINDOWS下载页面: http://git-scm.com/downlo...
  • haibin8473
  • haibin8473
  • 2017年12月30日 17:31
  • 45
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:托管态update更新异常——a different object with the same identifier value was already associated withthe sess
举报原因:
原因补充:

(最多只允许输入30个字)