我正在嘗試爲Java服務器中的競爭條件使用休眠進行臨時解決方法。代碼最初看起來是這樣的:在單個線程中導致死鎖的單休眠會話
s = sessionFactory.openSession();
Object o1 = dao.getMostRecentVersionOfObject(key, s);
if (o1.performSomeTimeConsumingTask() == Looks.Ok) {
Transaction t = s.beginTransaction();
dao.update(o1, s);
t.commit();
}
原來的問題是,如果2級不同的線程得到相同的代碼塊在大致相同的時間,他們都將嘗試並獲得對象的同一版本,所以第二個將永遠失敗。由於存在多個負載均衡的服務器,所以真正解決這個問題的方法是使用分佈式鎖定系統來確保版本保持同步,並且事務不會踩在其他腳趾上。但是,由於用戶已經發現這是一個問題,並且針對此問題的長期解決方案需要時間來開發,所以我決定通過檢查對象是否在交易前更新來添加臨時黑客行爲開始。我創建了第二個會話來執行此版本檢查。如果有更新,我使用第二次會話來填充對象的字段,然後保存它。因此,新的代碼看起來有點像這樣:
Session s = sessionFactory.openSession();
Session transactionSession = s;
Object o1 = dao.getMostRecentVersionOfObject(key, s);
int version = o1.getVersion();
if (o1.performSomeTimeConsumingTask() == Looks.Ok) {
Session newerSession = sessionFactory.openSession();
Object newerObject = dao.getMostRecentVersionOfObject(key, newerSession);
if (newerObject.getVersion() > version) {
// update fields...
transactionSession = newSession;
}
}
Transaction t = transactionSession.beginTransaction();
dao.update(o1, transactionSession);
t.commit();
這個代碼在幾個環境,但在最重要的一個失敗,因爲報告的僵局。這發生在沒有第二個併發請求時 - 第二個會話被創建,檢查版本,然後在第一個會話執行提交事務時被忽略。我懷疑這個問題要麼是環境問題(但我不明白爲什麼會這樣),或者說hibernate不喜歡使用第二個會話,但這只是一個有教養的猜測。我特別困惑,因爲只有一個事務,爲什麼hibernate會報告這是一個死鎖。
關於此任何想法非常感謝!
當報告死鎖時,不同的線程在哪裏?如果你得到StaleObjectException –
它是在提交上,這裏的另一種解決方案是試圖重複事務/工作。 – xtro