我使用Hibernate和Joined-SubClasses將類層次結構映射到 數據庫。不幸的是,當一個對象被更新而另一個線程試圖加載相同的對象時,這會導致死鎖。使用將 映射到單個表的對象,這不成問題。這似乎是MSSQL 在類層次結構的表上獲取鎖的方式造成的。Hibernate與MSSQL加入子類死鎖
當Hibernate從數據庫加載一個對象時,它使用SELECT與JOIN:
SELECT ...
FROM
subclass
LEFT JOIN class
ON ...
WHERE ...
當Hibernate更新該子類它的一個目的:
UPDATE
class
SET ...
WHERE ...
UPDATE
subclass
SET ...
WHERE ...
的問題是,如果一個對象在兩個更新語句之間加載,它會導致死鎖。 SELECT語句似乎鎖定了另一個 之後的兩個表。那麼,什麼似乎發生的是:
- 線程1個負載的目標和地方共享的兩個表
- 線程1執行在類表中的UPDATE語句鎖和升級的類表 鎖獨佔鎖。
- 線程2試圖通過執行SELECT語句加載同一個對象,它 地方上的子類表的共享鎖,然後等待直到在類表中的排他 鎖被釋放
- 線程1執行UPDATE語句對於子類表,它希望 將其在子類表上的鎖升級爲排它鎖,但 表已被線程2鎖定,該線程正在等待線程1
- 線程2由於死鎖而中止線1
死鎖圖看起來像這樣:Deadlock Graph
這些對象經常更新安靜,並且這會導致始終造成死鎖,甚至在加載單個對象時甚至會導致 。我也嘗試用 HSQLDB重現問題,但是它不會死鎖,HSQLDB似乎要麼將兩個表都鎖定爲 一次,要麼等待它可以同時鎖定兩個表,所以這似乎是一個問題,只有 發生在MSSQL中。
如果不修改 模式(索引除外),用Hibernate避免這個問題的解決方案是什麼?
我將Hibernate放在一邊問你的問題,這實際上是一個比Hibernate問題更多的MSSQL問題(如果適當標記它,你可能會獲得更多的牽引力)。無論如何你正在使用什麼事務隔離? PS:甚至不嘗試重現HSQLDB的問題(不確定使用的是哪個版本,但HSQLDB 1.8.2僅支持READ_UNCOMMITTED隔離級別,因此情況有很大不同)。 – 2010-09-02 15:02:24
也許,但加載一個對象的事實在兩個表上創建了一個連接,並且對象的更新創建了2個獨立的UPDATE語句來自Hibernate。如果我離開Hibernate,那麼解決方案可能是在單獨的事務中運行這兩個更新,或者更改SELECT語句。但這是我不能做的事情,因爲這些語句是由Hibernate生成的。 我首先使用HSQLDB 1.8.x進行了測試,注意到它不起作用,然後切換到2.0,這延遲了線程2的SELECT語句,直到線程1的事務被提交爲止。 – Reboot 2010-09-02 15:45:55
陳述的產生與否與事實無關,這是我的觀點。只要提出一個關於**這個**特定場景的問題(順便說一句,在單獨的查詢中運行更新不會)。但隨時忽略我的建議:) – 2010-09-02 19:50:17