질문 :
업데이트 : 이유는 무엇 table B
에 외래 키 제약 조건 table A
에 행을 삽입 한 후 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
나는 각각 동일한 시간 슬롯 (각각 같은
$timeSlotID
에 대한 예약을, 약 100 명의 동시 사용자와 내 서버 부하 테스트입니다 사용자).- 트랜잭션을 사용하지 않으면 (
cn.setAutoCommit(false);
,cn.commit()
등을 제거하십시오.)이 문제가 발생하지 않습니다.
환경 :
- 의 PostgreSQL 9.2.4
- 톰캣 7.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'는 두 쿼리에 대해 동일한 값입니다. "they"가 부하 테스트의 사용자 세션 인 경우 올바른 것입니다. 지금 나의 부하 테스트를 되돌아 본다; 무작위'timeSlotId'는 무작위가 아니며 모든 "user"에 대해 동일한'timeSlotId'를 선택했습니다. 그렇습니다. 모든 "사용자"가 동일한 'time_slot'행을 동시에 업데이트하려고했습니다. 그런데 왜이 문제는 트랜잭션을 사용할 때만 존재합니까? – Mike
나는 그것을 볼 수 있지만, 100 개의 동시 세션으로이 세션을 실행하고 있는데, 그 중 어떤 세션이 교착 상태가 발생할 수있는 'timeSlotID'를 사용한다면 –