Session A가 range를 읽고 lock을 유지하며, Session B는 priority 25 INSERT, Session C는 job_id 103 UPDATE를 시도하고 Session O가 COMMIT 후 결과를 봅니다.
MySQL 잠금 읽기: SELECT ... FOR UPDATE와 Next-Key Lock
locking read · next-key interval · data_locks이 Lab에서 답할 질문
같은 tenant_id range에서 plain SELECT와 FOR UPDATE, 그리고 isolation level이 Session B INSERT와 Session C UPDATE의 wait를 어떻게 바꾸나요?
jobs table, idx_tenant_priority_job, tenant_id = 7 range와 job_id 102·103 결과 rows를 고정합니다.
실행 SQL
SELECT job_id, priority, revision, note
FROM lock_jobs FORCE INDEX (idx_tenant_priority_job)
WHERE tenant_id = 7
AND priority >= 20
AND priority < 40
ORDER BY priority, job_id
FOR UPDATESession A가 보유한 record·gap·next-key lock과 B → A, C → A wait edge가 variant별로 달라집니다.
range predicate, holder result rows, B와 C의 시도, Session A COMMIT 뒤 최종 완료 순서는 동일합니다.
REPEATABLE READ + SELECT ... FOR UPDATE에서 COMMIT 전 누가 기다릴까요?
RR · FOR UPDATE variant의 wait graph 단계를 열어 Session A COMMIT 전에 누가 무엇을 기다리는지 확인하세요.
- 어디를 보나요?
- Trace corridor의 wait edge에서 각 edge의 indexName, lockMode, lockData를 함께 읽습니다.
- 이동할 화면
RR · FOR UPDATE · wait graph
무엇이 보여야 하나요?
이 variant에는 wait edge가 두 개 있습니다. Session C의 job_id 103 UPDATE는 PRIMARY row lock을 기다리고, Session B의 priority 25 INSERT는 idx_tenant_priority_job의 LOCK_DATA (7, 30, 103) 앞 gap을 기다립니다. 둘 다 Session A COMMIT 전 상태입니다.
근거 경계- Captured
- data_lock_waits의 C → A와 B → A wait edge와 lock 속성
Checkpoint · evidence로 설명하기세 variant의 captured wait edge는 어떻게 다르나요?답과 근거 확인
rr-plain은 wait edge가 없고, rr-for-update는 C → A와 B → A가 함께 있으며, rc-for-update는 C → A row wait만 남습니다. Session A COMMIT 뒤 waiting statement가 완료됩니다.
근거 경계- Captured
- data_lock_waits의 variant별 wait edge
locking read는 반환 rows뿐 아니라 index record와 그 앞 gap을 보호할 수 있으며, isolation level이 INSERT를 막는 range protection을 바꿉니다.
이 Lab은 access path에서 시작해 row version과 lock wait까지 이어진 8개 Lab 경로의 끝입니다. 이전 Lab의 consistent read와 나란히 비교해 마무리하세요.
용어 확인
record lock처음 다루는 Lab 08- index의 특정 record에 설정되어 충돌하는 UPDATE나 locking read를 기다리게 하는 lock입니다.
gap lock처음 다루는 Lab 08- index record 사이의 간격을 보호해 그 범위에 들어오는 INSERT와 충돌할 수 있는 lock입니다.
next-key lock처음 다루는 Lab 08- index record lock과 그 record 앞의 gap lock을 결합해 range를 보호하는 InnoDB lock 형태입니다.
lock wait처음 다루는 Lab 08- 요청한 lock이 다른 transaction의 호환되지 않는 lock과 충돌해 해제될 때까지 statement가 멈춘 상태입니다.
READ COMMITTED처음 다루는 Lab 07- 각 consistent read가 statement 시작 시점의 새 snapshot을 사용하는 isolation level입니다.
tenant_id = 7이고 priority가 20 이상 40 미만인 task row를 조회합니다.
Session A가 조회한 row와 그 사이 index gap을 잠그기 때문에 job_id 103 UPDATE와 job_id 106 INSERT가 모두 COMMIT까지 기다립니다.
같은 SELECT를 세 조건으로 실행해서 Session B의 INSERT와 Session C의 UPDATE가 바로 실행되는지, COMMIT을 기다리는지 비교합니다.
- 현재 비교 조건
- REPEATABLE READ + SELECT ... FOR UPDATE
- Session A
- Session A · SELECT 실행
- Session B
- Session B · INSERT 시도
- Session C
- Session C · UPDATE 시도
Session A가 SELECT하기 전
WHERE 절은 lock_jobs에서 tenant_id = 7인 row만 보고, 그중 priority가 20 이상 40 미만인 row를 고릅니다.
| tenant_id | priority | job_id |
|---|---|---|
| 7 | 10 | 101 |
| 7 | 20 | 102 |
| 7 | 30 | 103 |
| 7 | 40 | 104 |
| 7 | 50 | 105 |
tenant_id = 7 · priority >= 20 · priority < 40Session A가 SELECT한 뒤
Session A는 job_id 102, 103을 읽고 FOR UPDATE lock을 유지합니다. Session C는 job_id 103 row lock에서, Session B는 priority 25를 넣을 index gap에서 기다립니다.
SELECT ... FOR UPDATE- job_id 102tenant_id 7 · priority 20
- job_id 103tenant_id 7 · priority 30
Session A가 COMMIT한 뒤
Session A가 COMMIT하면 lock이 풀리고 기다리던 UPDATE와 INSERT가 이어서 완료됩니다.
- UPDATED · job_id 103
- INSERTED · job_id 106
| tenant_id | priority | job_id | state |
|---|---|---|---|
| 7 | 20 | 102 | UNCHANGED |
| 7 | 25 | 106 | INSERTED |
| 7 | 30 | 103 | UPDATED |