Hibernate事务异常,查询和更新并存卡死表

最近项目中遇到一个问题:查询和更新事务异步运行,当并发出现在某个表上时,SQLServer数据库会将该表锁死,导致程序无法执行。但是Oracle和MySql不会。项目采用Hibernate作为ORM框架,问题集中在多对多映射上。

项目问题暴露和解决顺序如下:

系统中有两个实体类,A类和B类,它们之间为多对多关联。项目目标是根据A的名称,来找到B,然后将B删除。如果在A下面当前只有一条B记录那么不会出现问题,但是如果有多条B记录那么将会产生如下异常:a different object with the same identifier value was already associated with the session。错误原因:在hibernate中同一个session里面有了两个相同标识但是是不同实体。
解决方法:session.clear();

之所以能够在同一个session中出现不同的对象,因为我们在根据A删除B时并没有提交事务,第一次我们查询出来B并且级联出来A将其放到session中,此时将A和B的关系断开,但是并没有提交事务,当再次断开A和另外一个B对象时,犹豫两个B对象都将A放到了session中导致出现了上述异常。通过每次断开关系后执行clear能够将session中A对象清空。但是可能会产生如下异常:"Found two representations of same collection"异常。该异常原因同上。

解决方法:采用本地sql的方式。

但是很不幸,原先的单元测试都是在Oracle上,以为都解决了问题,但是当换到SQLServer上之后,出现了将表卡死的现象。问题原因如第一段描述。该问题通过理解数据库的事务隔离级别来定位,既然是不同的事务并发导致的死锁,那么我们只要将所有的操作放到同一个事务中就没有问题了,并且不会出现上述描述的异常,原因猜测是由于是同一个session那么hibernate会将两个不同对象(不同地址)进行merge为同一个对象。这样所有的问题迎刃而解。

-------------------------------------------------------------------------------------------------------------------------

后记:Hibernate可以自定义事务隔离级别,在hibernate.cfg.xml中可以配置

1:读操作未提交(Read Uncommitted)
2:读操作已提交(Read Committed)
4:可重读(Repeatable Read)
8:可串行化(Serializable)

因此,数字4表示“可重读”隔离级别。如果要使以上语句有效,应把此语句行前的注释符“#”去掉:

#hibernate.connection.isolation 4

也可以在配置文件hibernate.cfg.xml中加入以下代码:

把隔离级别设置为4

<session-factory>
<property name=” hibernate.connection.isolation”>4</property>
……
</session-factory>

当创建Connection对象时,其事务隔离级别取决于驱动程序,但通常是所涉及的数据库的缺省值。用户可通过调用setIsolationLevel方法来更改事务隔离级别。新的级别将在该连接过程的剩余时间内生效。要想只改变一个事务的事务隔离级别,必须在该事务开始前进行设置,并在该事务结束后进行复位。我们不提倡在事务的中途对事务隔离级别进行更改,因为这将立即触发commit方法的调用,使在此之前所作的任何更改变成永久性的。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值