老问题新讨论:再论a different object with the same
2015-05-18 08:51
204 查看
转载▼
问题:这个著名的托管态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级别或者事务级别上分隔开.
现在问题的新变化:
hibernate3.0以后,getCurrentSession()技术的出现,session pool的出现,session不再需要手动open,也不需要手动关闭,反而使问题复杂化
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()完成后,其操作的对象是托管态.
老问题新讨论:再论a different object with the same
(2010-07-22 01:41:34)转载▼
标签:adifferentobjectwiththesameidentifiervaluewasalreadyassociat | 分类: java和数据库 |
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级别或者事务级别上分隔开.
现在问题的新变化:
hibernate3.0以后,getCurrentSession()技术的出现,session pool的出现,session不再需要手动open,也不需要手动关闭,反而使问题复杂化
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()完成后,其操作的对象是托管态.
相关文章推荐
- 80后创业的常见问题收集(欢迎讨论)
- 些基础的 Linux 问题与讨论:
- 关于SQL Server将一列的多行内容拼接成一行的问题讨论
- 有关软件工程的问题的分析和讨论及课后的作业3
- 整数划分问题继续讨论(woj Problem 1058 Exchange)
- 在国外SEO论坛上讨论的几个小问题
- 讨论2:对于程序员学历是不是问题?
- 有关ListView优化机制及滑动时数据错乱问题的讨论
- scanf函数简单问题讨论
- 外方的讨论问题方法
- 关于网页元素的定位问题及offsetParent的讨论
- 对Spring事务一些问题的讨论
- 和周杰讨论:DB2连接问题
- [讨论] Excel Range写入大量数据的效率问题
- javascript中的“=”等号个数问题的讨论
- Makefile 中向下传参问题讨论
- [ios]关于tablelist里的每个按钮点击时传值的问题讨论
- 《Linux内核修炼之道》精华分享与讨论(8)——内核学习的心理问题
- [技术讨论]业务建模的一些问题和工具选择的问题
- SDWebImage使用SDWebImageRefreshCached后,图片没有刷新的问题讨论