代码之家  ›  专栏  ›  技术社区  ›  Reboot

Hibernate使用MSSQL连接子类死锁

  •  3
  • Reboot  · 技术社区  · 14 年前

    我使用Hibernate和连接的子类将类层次结构映射到 数据库不幸的是,当对象在 不同的线程正在尝试加载相同的对象。使用已映射的对象 对于单个表,这没有问题。这似乎是由MSSQL 获取类层次结构表上的锁。

    当Hibernate从数据库加载对象时,它会使用带有连接的SELECT:

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

    Hibernate更新此子类的对象时会执行以下操作:

    UPDATE
        class
    SET ...
    WHERE ...
    
    UPDATE
        subclass
    SET ...
    WHERE ...
    

    问题是,如果在两个update语句之间加载对象,则 导致死锁。SELECT语句似乎一个接一个地锁定了这两个表 另一个因此,似乎发生的是:

    1. 线程1加载一个对象并在两个表上放置共享锁
    2. 线程1执行类表的UPDATE语句并升级 将类表锁定为独占锁。
    3. 线程2试图通过执行SELECT语句加载相同的对象,它 在子类表上放置共享锁,然后等待直到 类表上的锁已释放
    4. 线程1执行子类表的UPDATE语句 将子类表上的锁升级为独占锁,但 表已被线程2锁定,该线程正在等待线程1
    5. 由于线程1发生死锁,线程2中止

    死锁图如下所示: Deadlock Graph

    这些对象经常安静地更新,这会导致死锁,甚至 仅加载单个对象时。我还试图用 HSQLDB但它不会死锁,HSQLDB似乎会将两个表都锁定在 一次或等待,直到它可以锁定这两个,所以这似乎是一个问题,只有 与MSSQL一起发生。

    有什么解决方案可以避免Hibernate在不修改 架构(索引除外)?

    2 回复  |  直到 14 年前
        1
  •  1
  •   Paul Williams    14 年前

    你打开电源了吗 SQL Server deadlock trace flags 1204 or 1222 ? 这将有助于准确识别导致死锁的资源。请参阅MSDN文章 Detecting and Ending Deadlocks 了解更多信息。

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

        2
  •  0
  •   Danny Thomas    14 年前

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