問:
更新時間: 爲什麼插入一個行table A
與外鍵約束table B
,然後更新行table B
的是,在交易table A
引用插入的行造成僵局?
PSQL JDBC事務導致死鎖
場景:
reservation.time_slot_id
有一個外鍵約束time_slot.id
。保留時提出了以下SQL運行:
BEGIN TRANSACTION INSERT INTO reservations (..., time_slot_id) VALUES (..., $timeSlotID) UPDATE reservations SET num_reservations = 5 WHERE id = $timeSlotID COMMIT
我的負載測試我的服務器有大約100個併發用戶,同一時隙(相同
$timeSlotID
每個各進行預訂用戶)。- 如果我不使用交易(刪除
cn.setAutoCommit(false);
,cn.commit()
等),則不會發生此問題。
環境:
- 的PostgreSQL 9.2.4
- Tomcat的V7.0
- JDK 1.7.0_40
- 公地DBCP-1.4.jar
- commons-pool-1.6.jar
- PostgreSQL相關9.2-1002.jdbc4.jar
代碼:
// endpoint start
// there are some other SELECT ... LEFT JOIN ... WHERE ... queries up here but they don't seem to be related
...
// create a reservation in the time slot then increment the count
cn.setAutoCommit(false);
try
{
st = cn.prepareStatement("INSERT INTO reservation (time_slot_id, email, created_timestamp) VALUES (?, ?, ?)");
st.setInt (1, timeSlotID); // timeSlotID is the same for every user
st.setString(2, email);
st.setInt (3, currentTimestamp);
st.executeUpdate();
st.close();
st = cn.prepareStatement("UPDATE time_slot SET num_reservations = 5 WHERE id = ?"); // set to 5 instead of incrementing for testing
st.setInt(1, timeSlotID); // timeSlotID is the same for every user
st.executeUpdate();
st.close();
cn.commit();
}
catch (SQLException e)
{
cn.rollback();
...
}
finally
{
cn.setAutoCommit(true);
}
...
// endpoint end
PSQL錯誤:
ERROR: deadlock detected
DETAIL: Process 27776 waits for ExclusiveLock on tuple (2,179) of relation 49817 of database 49772; blocked by process 27795.
Process 27795 waits for ShareLock on transaction 3962; blocked by process 27777.
Process 27777 waits for ExclusiveLock on tuple (2,179) of relation 49817 of database 49772; blocked by process 27776.
Process 27776: UPDATE time_slot SET num_reservations = 5 WHERE id = $1
Process 27795: UPDATE time_slot SET num_reservations = 5 WHERE id = $1
Process 27777: UPDATE time_slot SET num_reservations = 5 WHERE id = $1
HINT: See server log for query details.
STATEMENT: UPDATE time_slot SET num_reservations = 5 WHERE id = $1
'timeSlotID'的值是什麼,他們很可能試圖更新相同的記錄。 –
你指的是「他們」? try塊內的代碼是完整的代碼。因此,'timeSlotID'對於兩個查詢都是相同的值。 如果「他們」是來自負載測試的用戶會話,那麼你是正確的。現在回顧我的負載測試;隨機'timeSlotId'不是隨機的,並且爲每個「用戶」選擇相同的'timeSlotId'。 所以是的,每個「用戶」都試圖同時更新同一個'time_slot'行。但是爲什麼只有在使用事務時才存在這個問題? – Mike
我看到了,但是你正在執行100個併發會話,如果其中任何會話使用相同的'timeSlotID',可能會導致死鎖 –