Hibernate使用MSSQL加入了子类死锁

时间:2010-09-02 12:24:56

标签: java sql-server hibernate deadlock

我正在使用Hibernate和Joined-SubClasses将类层次结构映射到a 数据库。不幸的是,当a更新对象时,这会导致死锁 不同的线程正在尝试加载相同的对象。使用映射的对象 这对单个表来说没问题。这似乎是导致MSSQL的方式 获取类层次结构表的锁。

当Hibernate从数据库加载一个对象时,它使用带有JOIN的SELECT:

SELECT ...
FROM
    subclass
    LEFT JOIN class
        ON ...
WHERE ...

当Hibernate更新此子类的对象时,它会:

UPDATE
    class
SET ...
WHERE ...

UPDATE
    subclass
SET ...
WHERE ...

问题是如果在两个更新语句之间加载一个对象呢 导致僵局。 SELECT语句似乎一次锁定了2个表 另一个。所以似乎发生的事情是:

  1. 线程1加载一个对象并在两个表上放置共享锁
  2. 线程1执行类表的UPDATE语句并升级 将类表锁定为独占锁。
  3. 线程2尝试通过执行SELECT语句来加载同一个对象 在子类表上放置一个共享锁,然后等待独占 已释放类表上的锁
  4. 线程1执行它想要的子类表的UPDATE语句 将它在子类表上的锁升级为独占锁,但是 表已被线程2锁定,它正在等待线程1
  5. 线程2由于线程1的死锁而中止
  6. 死锁图如下所示:Deadlock Graph

    这些对象经常更新安静,这甚至会导致死锁 只加载一个对象时我也尝试重现这个问题 HSQLDB然后它没有死锁,HSQLDB似乎要么锁定两个表 一次或等到它可以锁定两者,所以它似乎只是一个问题 与MSSQL一起发生。

    如何在不修改的情况下避免Hibernate的这个问题 架构(索引除外)?

2 个答案:

答案 0 :(得分:1)

你打开了SQL Server deadlock trace flags 1204 or 1222吗?这将有助于确切地确定导致死锁的资源。有关详细信息,请参阅Detecting and Ending Deadlocks上的MSDN文章。

这些表上是否有索引?如果是这样,如果应用程序获取聚簇索引上的锁,然后尝试通过查找非聚集索引来尝试在同一个表上获取更多锁,则会发生死锁。

答案 1 :(得分:0)

在我看来,这些更新需要在单个事务中以原子方式完成。不幸的是,我没有很多关于Hibernate的背景知识,所以我会把它留给其他人指出你在正确的方向。