2014-01-05 1 views
1

무한한 시간에이 행을 사용할 때까지 한 사용자가 한 행을 잠 그려면 끝내야합니다. 따라서 다른 사용자는이 행을 직접 잠글 수 없습니다. 데이터베이스 수준에서 할 수 있습니까?PostgreSQL Lock Row on indefinitely time

답변

1

장기간 트랜잭션을 사용하여 수행 할 수 있지만 성능 문제가있을 수 있습니다. 이것은 낙관적 인 동시성 제어를위한 일로 보입니다.

고객 SELECT 1 FROM mytable WHERE clause to match row FOR UPDATE;을 거래하기 만하면됩니다. 그런 다음 거래가 끝날 때까지 열어 두십시오. 이 문제는 테이블이 삭제 된 데이터로 채워지고 인덱스가 쓸모없는 블록을 가리키는 항목으로 채워지는 테이블 및 인덱스가 부풀어 오르는 문제를 일으킬 수 있다는 점에서 문제가됩니다.

advisory lock을 사용하는 것이 훨씬 더 좋습니다. 잠금 장치가 열려있는 보류 연결을 유지해야하지만 열려있는 유휴 트랜잭션을 유지할 필요가 없으므로 잠금이 훨씬 적습니다. 행을 업데이트하려는 트랜잭션은 충돌하는 권고 자물쇠를 명시 적으로 확인해야합니다. 그렇지 않으면 잠금이 설정되지 않은 것처럼 진행할 수 있습니다. 이 접근법은 많은 테이블 (자문 잠금 네임 스페이스가 한정되어 있기 때문에) 또는 동시 잠금이 많아 (연결 수 때문에) 잘 조정되지 않습니다.

트리거를 사용하여 권고 자물쇠를 확인하고 클라이언트 응용 프로그램이 항상 권고 자물쇠를 명시 적으로 얻을 수 있는지 확인할 수 없을 때까지 기다릴 수 있습니다. 그러나 이로 인해 교착 상태 문제가 발생할 수 있습니다.

그런 이유로 가장 좋은 방법은 사용자 ID를 기록하는 locked_by 필드와 잠긴 시간을 기록하는 locked_time 필드를 갖는 것입니다. 응용 프로그램 수준에서 및/또는 트리거를 사용하여 수행하십시오. 동시 잠금 시도를 처리하려면 optimistic concurrency control 기술을 사용할 수 있습니다. 의 WHERE 절에 다른 사람이 먼저 도착하면 locked_bylocked_time을 설정하면 일치하지 않으므로 행 수가 0이되고 잃어버린 것을 알게됩니다 자물쇠 경주 그리고 다시 확인해야합니다. 그 WHERE 절은 보통 locked_bylocked_time을 테스트합니다.

UPDATE t 
SET locked_by = 'me' AND locked_time = current_timestamp 
WHERE locked_by IS NULL AND locked_time IS NULL 
AND id = [ID of row to update]; 

(이것은 다른 사람에 뛰어 전체 거래를 한 경우도 상관없는 잠금을 잡는 단순화 낙관적 잠금 모드 당신이 원하는 경우 엄격한 순서 :. 그래서 당신은 같은 것을 써서 행 버전 열을 사용하거나 last_modified 열이 변경되지 않았는지 확인하십시오.

+0

"locked_by IS NULL 및 locked_time IS NULL"인 모든 행을 쿼리 업데이트처럼 보이지만 한 행만 업데이트하는 방법은 무엇입니까? 그리고 응용 프로그램이 떨어지고 행이 잠긴 상태 일 때 상황이 될 수 있다고 생각하지만 사용자가 프로그램을 다시 시작할 때 locked_by = 'me'라는 행이 이미 존재하므로 먼저 행을 가져야합니다. 추신 : 내 영어 죄송합니다 – Miles

+0

@ 마일 예, 오히려. 관심있는 ID를 포함해야합니다. 결정된. –

+0

@Miles 앱이 실패하면 "무기한으로 잠근"과 동시에 "자동으로 잠금 해제시 잠금 해제"를 할 수 없습니다. PostgreSQL에 열려있는 TCP 연결 (권고 잠금 또는 장시간 실행 tx)에 의존해야 할 것입니다 (그러나 DB가 많은 쓰기 부하를받는 경우 장기 실행 tx는 실제로 좋지 않습니다). –