2013-10-11 4 views
1

내 응용 프로그램에 간헐적으로 교착 상태가 발생합니다. 신청서에 EMPLOYEE (ID (PK), NAME, SAL)과 같은 1 개의 테이블이 있으며 2 개의 세션이 있습니다.SELECT FOR UPDATE에서 데이터베이스 교착 상태가 발생했습니다.

세션 1 :

SELECT ID, NAME, SAL FROM EMPLOYEE WHERE SAL= (SELECT MIN(SAL) FROM EMPLOYEE) FOR UPDATE 
Let say the query return EMPLOYEE ROW having ID=2 
then application does some processing like rs.updateInt(ID_SAL, 10); 

세션 2 : (다른 비즈니스 로직)

SELECT ID, NAME, SAL FROM EMPLOYEE WHERE ID=2 FOR UPDATE. 

그래서, 응용 프로그램에서 두 세션이 동일한 행을 업데이트하려고 (예에서 ID와 행 = 2) 이러한 상황이 예상되므로 SELECT .. FOR UPDATE가 도움이 될 것이라고 생각합니다.

내가 잘못 했나요? 나는 SELECT FOR UPDATE가 행을 락하고 다른 세션이 같은 행을 업데이트하려고 할 때 세션 1이 완료 될 때까지 기다릴 것이라고 가정한다. 내가 UPDATE FOR SELECT는 행을 흔들 다른 세션이 동일한 행을 업데이트하려고 할 때, 그것은 세션까지 1 완료를 대기하는 있으리라 믿고있어

답변

4

.

정확하게 맞습니다. 그러나이 행이나 세션을 종료 할 때 트랜잭션을 닫아야합니다. 를 업데이트하고 공정이 이미 잠겨 (활성하지만 여전히 세션 및 트랜잭션한다) ID = 1 다음 레코드로 이동, 1 잠금 ID = 2 행

과정 : 문제에 대한 가능한 상황은 다음이다 ID = 1,가는 행 ID가 = 2

그래서 1 레코드 ID를 기다리는 처리합니다 (그러나 세션 및 트랜잭션이 여전히 활성 상태) = 1 개을 길게 레코드 ID = 2 개

프로세스 2가에 행을 잠급니다 레코드 ID = 2를 기다리고 레코드 ID = 1을 보유하십시오.

이것은 deadlock입니다. 다른 프로세스를 위해 레코드를 완료 한 후에 트랜잭션을 완료해야합니다.

하나의 트랜잭션에서 여러 레코드를 업데이트해야만 작업을 완료 한 후에 모든 레코드를 함께 잠그면됩니다.

+0

빠른 응답을 위해 Nicolai에게 감사드립니다. 예, 당신은 설명에서 정확합니다. 두 세션 모두 처리가 완료되면 트랜잭션을 커밋/롤백합니다. 즉 rs.updateRow()입니다. 세션 1에서 내 응용 프로그램 프로세스는 단 1 행 (참고 : 세션 1 쿼리는 여러 행을 반환 할 수 있지만 한 행만 처리합니다). 그리고 세션 2 쿼리는 항상 1 행을 반환합니다. –

+0

가장 중요한 것은 두 프로세스에서 다른 레코드로 전환하기 전에 무료 (전체 트랜잭션 또는 세션 닫기) 레코드 또는 대량의 레코드입니다. – Nicolai