0 / 3
Lock 호환(Lock Compatibility)
공유 · 공유
이미 걸린 Lock과 새로 요청한 Lock을 함께 걸 수 있으면 뒤의 트랜잭션은 바로 실행되고, 함께 걸 수 없으면 기다린다.
둘 다 읽기만 할 때 공유 Lock끼리 함께 걸리는지 본다.
1 / 3
T1이 공유 Lock을 걸고 읽는다
T1이 X에 공유 Lock을 걸고 10을 읽는다.
2 / 3
T2도 바로 읽는다
T2도 X에 공유 Lock을 건다. 공유 Lock끼리는 함께 걸 수 있어서 T2는 기다리지 않는다.
3 / 3
결과: 공유 Lock끼리는 함께 걸린다
읽기끼리는 값을 바꾸지 않으므로 공유 Lock은 함께 걸어도 된다.
1 / 5
T1이 공유 Lock을 걸고 읽는다
T1이 X에 공유 Lock을 걸고 10을 읽는다.
2 / 5
T2는 기다린다
T2는 쓰려고 배타 Lock을 요청한다. X에는 T1의 공유 Lock이 걸려 있어서 함께 걸 수 없다.
3 / 5
T1이 Lock을 푼다
T1이 다 읽고 X의 Lock을 푼다. 기다리던 T2가 이제 Lock을 걸 수 있다.
4 / 5
T2가 이제 쓴다
T2가 X에 배타 Lock을 걸고 9를 쓴다.
5 / 5
결과: 함께 걸 수 없다
T1이 읽는 도중에 값이 바뀌지 않도록 T2는 T1이 Lock을 풀 때까지 기다린다.
1 / 5
T1이 배타 Lock을 걸고 쓴다
T1이 X에 배타 Lock을 걸고 9를 쓴다.
2 / 5
T2는 기다린다
T2는 읽으려고 공유 Lock을 요청한다. X에는 T1의 배타 Lock이 걸려 있어서 읽기도 막힌다.
3 / 5
T1이 끝난다
T1이 Commit하고 X의 Lock을 푼다. 기다리던 T2가 이제 Lock을 걸 수 있다.
4 / 5
T2가 이제 읽는다
T2가 X에 공유 Lock을 걸고 확정된 9를 읽는다.
5 / 5
결과: 함께 걸 수 없다
배타 Lock은 쓰는 도중의 값을 다른 트랜잭션이 읽지 못하게 막는다.
1 / 5
T1이 배타 Lock을 걸고 쓴다
T1이 X에 배타 Lock을 걸고 9를 쓴다.
2 / 5
T2는 기다린다
T2도 쓰려고 배타 Lock을 요청하지만 T1의 배타 Lock 때문에 기다린다.
3 / 5
T1이 끝난다
T1이 Commit하고 X의 Lock을 푼다. 기다리던 T2가 이제 Lock을 걸 수 있다.
4 / 5
T2가 이제 쓴다
T2가 X에 배타 Lock을 걸고 9에서 1을 빼 8을 쓴다.
5 / 5
결과: 함께 걸 수 없다
두 쓰기가 섞이지 않고 하나씩 차례로 실행된다.
정리:공유 Lock끼리만 함께 걸 수 있고, 배타 Lock이 하나라도 있으면 뒤의 트랜잭션은 기다린다.
1 / 5
T1이 테이블 전체에 Lock을 건다
T1이 행1을 고치려고 주문 테이블 전체에 배타 Lock을 건다.
2 / 5
T2는 기다린다
T2는 다른 행인 3번 주문을 고치려 한다. 그런데 테이블 전체에 Lock이 걸려 있어서 기다린다.
3 / 5
T1이 끝난다
T1이 Commit하고 테이블의 Lock을 푼다.
4 / 5
T2가 이제 고친다
T2가 테이블에 배타 Lock을 걸고 행3을 고친다.
5 / 5
결과: 병행성이 낮다
T1과 T2는 서로 다른 행을 고쳤는데도 차례로 실행됐다.
1 / 5
T1이 행1에만 Lock을 건다
T1이 고칠 행1에만 배타 Lock을 건다.
2 / 5
T2도 바로 고친다
T2가 행3에 배타 Lock을 건다. T1의 Lock은 행1에만 걸려 있어서 T2는 기다리지 않는다.
3 / 5
T1이 끝난다
T1이 Commit하고 행1의 Lock을 푼다.
4 / 5
T2가 끝난다
T2가 Commit하고 행3의 Lock을 푼다.
5 / 5
결과: 병행성이 높다
서로 다른 행을 고치는 트랜잭션은 함께 실행됐다.
대가:행마다 Lock을 걸어서 관리할 Lock 수가 늘어난다.참고:행 Lock이 너무 많아지면 이를 테이블 Lock 하나로 바꾸는 DBMS도 있다(SQL Server 등). 이를 Lock 확대(Lock Escalation)라고 한다. Oracle이나 MySQL(InnoDB)처럼 확대하지 않는 DBMS도 있다.
1 / 6
T1이 A를 읽는다
T1이 A에 공유 Lock을 걸고 100을 읽는다.
2 / 6
T1이 A의 Lock을 푼다
T1은 이 뒤에 B에도 Lock을 걸어야 한다. 그런데 여기서 A의 Lock을 먼저 풀었으므로, B에 Lock을 거는 순간 2PL 규칙을 어기게 된다.
3 / 6
T2가 끼어든다
A의 Lock이 풀렸으므로 T2가 A에 배타 Lock을 걸고 50을 뺀다.
4 / 6
T2가 이체를 마친다
T2가 B에 배타 Lock을 걸고 50을 더한 뒤 Lock을 모두 풀고 끝난다.
5 / 6
T1이 B를 읽는다
T1이 B에 공유 Lock을 걸고 읽는다. 이체가 이미 끝나서 150이다. Lock을 푼 뒤에 새 Lock을 걸었으므로 2PL을 어겼다.
6 / 6
결과: Lock을 걸어도 총액이 틀린다
T1이 A의 Lock을 너무 일찍 풀어서 그 틈에 T2의 이체가 끼어들었다.
1 / 7
확장 단계: A에 Lock을 건다
T1이 A에 공유 Lock을 걸고 100을 읽는다. 아직 B에 Lock을 걸지 않았으므로 A의 Lock을 풀지 않는다.
2 / 7
T2는 기다린다
T2가 A에 배타 Lock을 요청하지만 T1의 공유 Lock 때문에 기다린다. Lock을 일찍 푸는 방식에서는 여기서 T2가 끼어들었다.
3 / 7
확장 단계: B에 Lock을 건다
T1이 B에도 공유 Lock을 걸고 100을 읽는다. 이제 필요한 Lock을 모두 걸었다.
4 / 7
축소 단계: Lock을 푼다
T1이 총액 200을 구하고 Lock을 푼다. 이때부터 T1은 새 Lock을 걸 수 없다.
5 / 7
T2가 이제 이체한다
기다리던 T2가 A에 배타 Lock을 걸고 50을 뺀다.
6 / 7
T2가 이체를 마친다
T2가 B에 배타 Lock을 걸고 50을 더한다.
7 / 7
결과: 직렬 가능하다
모든 트랜잭션이 2PL을 지키면 번갈아 실행해도 하나씩 차례로 실행한 것과 결과가 같다. 이를 직렬 가능하다고 한다.
확장 단계:T1이 Read(B)까지 Lock을 걸기만 한다.축소 단계:T1이 unlock(A, B)부터 Lock을 풀기만 한다.
1 / 5
T1이 9를 쓴다
T1이 X에 배타 Lock을 걸고 9를 쓴다. 아직 Commit하지 않았다.
2 / 5
T1이 Commit 전에 Lock을 푼다
T1은 더 걸 Lock이 없어서 2PL 규칙상 X의 Lock을 풀어도 된다. 하지만 아직 Commit하지 않았다.
3 / 5
T2가 중간 값을 읽는다
T2가 X에 공유 Lock을 걸고 아직 확정되지 않은 9를 읽는다.
4 / 5
T1이 취소한다
결제가 실패해 T1이 Rollback하고 X는 10으로 돌아간다. T2가 읽은 9는 무효가 된다.
5 / 5
결과: 기본 2PL은 연쇄 복귀를 막지 못한다
2PL은 Lock을 하나라도 푼 뒤에는 새 Lock을 걸지 않는다는 순서만 정한다. Lock을 Commit 전에 풀지 뒤에 풀지는 정하지 않는다.
1 / 5
T1이 9를 쓴다
T1이 X에 배타 Lock을 걸고 9를 쓴다. Commit하거나 Rollback할 때까지 이 Lock을 풀지 않는다.
2 / 5
T2는 기다린다
T2가 X를 읽으려 하지만 T1의 배타 Lock 때문에 기다린다. 기본 2PL에서는 여기서 T2가 9를 읽었다.
3 / 5
T1이 취소하고 Lock을 푼다
T1이 Rollback해 X를 10으로 되돌린 뒤에야 Lock을 푼다.
4 / 5
T2가 확정된 값을 읽는다
기다리던 T2가 X에 공유 Lock을 걸고 확정된 10을 읽는다.
5 / 5
결과: 엄격한 2PL은 연쇄 복귀를 막는다
T2는 확정된 값만 읽었으므로 T1의 Rollback과 상관없다.
강력한 2PL:Rigorous 2PL이라고도 한다. 공유 Lock까지 모든 Lock을 Commit하거나 Rollback할 때까지 풀지 않는다. 연쇄 복귀를 막는 점은 엄격한 2PL과 같고, Commit한 순서대로 하나씩 실행한 것과 결과가 같다. 실제 DBMS는 대부분 이 방식을 쓴다.
1 / 5
T1이 A에 Lock을 건다
T1이 A에 배타 Lock을 걸고 A를 고친다.
2 / 5
T2가 B에 Lock을 건다
T2가 B에 배타 Lock을 걸고 B를 고친다.
3 / 5
T1이 T2를 기다린다
T1이 B를 고치려 하지만 T2의 배타 Lock 때문에 기다린다. T1은 A에 건 Lock을 풀지 않고 기다린다.
4 / 5
T2가 T1을 기다린다
T2도 A를 고치려 하지만 T1의 배타 Lock 때문에 기다린다. 이제 둘 다 상대가 Lock을 풀기만 기다린다.
5 / 5
결과: 교착상태
누가 끼어들지 않으면 두 트랜잭션 모두 Lock을 풀지 않아서 끝없이 기다린다.