浅谈 a different object with the same identifier value was already associated with the session错误

来源:互联网 发布:surface装mac 编辑:程序博客网 时间:2024/06/03 14:47

          开发一年都没有博客的习惯,以后要养成这种习惯,技术都是慢慢积累起来的。

         今天在开发中,遇到了这个问题 a different object with the same identifier value was already associated with the session:,这个意思很简单,就是说在用一个session里边有两个不同的对象,但是这两个对象却都有一个标识为,产生的原因无非就是在update的时候,new 一个对象,然后又setId所发生的,解决这个问题,有很多方式,但也要根据自己的业务场景来解决。

       在早先的hibernate3.0以前,经常是session忘记关闭没有clean,本该两个session的合为一个session,所以才会产生这个问题。

       而在hibernate 3.0 以后 getCurrentSession() session pool 技术的出现,在启动的session的时候不需要手动开启和关闭,反而使问题更加复杂化。

        比如在spring TransactionManger中,定义了各种隔离机制,比如:在一个事务下的方法,如果调用另外一个方法,则这个方法不需要开启事务,如果开启事务之后,那么必须等到这个事物完成之后,上一个事务才能继续,这就好比事务的嵌套,在这也介绍一下什么是嵌套事务。

       我们知道,数据库事务是为了保证数据库操作原子性而设计的一种解决办法。例如执行两条 update 当第二条执行失败时候顺便将前面执行的那条一起回滚。
      这种应用场景比较常见,例如银行转帐。A账户减少的钱要加到B账户上。这两个SQL操作只要有一个失败,必须一起撤销。
      但是通常银行转帐业务无论是否操作成功都会忘数据库里加入系统日志。如果日志输出与账户金额调整在一个事务里,一旦事务回滚日志也会跟着一起消失。这时候就需要嵌套事务。
      a different object with the same identifier value was already associated with the session
      这个问题的解决无非是两个方面:session和update()这两个方面解决
      1,、session方面
       从程序的角度进行分析,找到session的开始点和结束定。
       不过由于现在的代码越来越框架化,模块化,封装的越来越深,一般的开发者很难找到,尤其是现在session的管理都在业务层之外,通常都追溯到很高层的父类,尤其是和事务挂钩的时候,更加复杂,所以一般的session.clean(),session.close()都不一定能解决问题。
       2,、从update方面
      比较简单的方法就是用到marge()方法或者refresh(),evint() 方法,这两个方法是有一定的区别。
      首先marge()方法是将给定对象的状态复制到具有相同id的持久化对象,而给定的对象就不会关联到session,当然,也就是这个对象是托管状态的,而refresh()方法是重新读取session中的对象,会使之前的object的标示进行刷新一次,不过如果你的object属性是从表单传过来的值,那么如果使用refresh会把你的object传过来的值刷新掉,变成之前的值,所以也要根据自己的业务。
   evint()方法这个很简单,就是把持久化的对象变成游离态。
   以上就是这个问题从而引发的一些对问题的思考,如果有不对,希望大家能给予指出。
     

0 0