[question] 트랜잭션 격리 원리 / 데드락 / 트랜잭션 격리 수준
Closed this issue · 1 comments
JasonYoo1995 commented
JasonYoo1995 commented
트랜잭션 격리(Transaction Isolation)
- 어떤 트랜잭션이 특정 데이터를 접근하는 도중에는, 다른 트랜잭션이 해당 데이터를 접근하지 못하도록 막는 것.
- Race Condition과 비슷한 개념.
- 일반적으로 하나의 Row에 대한 얘기
- 상세 원리
- 특정 트랜잭션이 어떤 데이터를 Read 또는 Write를 시작하기 전에
해당 데이터에 Lock을 미리 걸어서
다른 트랜잭션이 해당 데이터를 접근하지 못하도록 막고
해당 데이터에 대한 연산을 마치면 Unlock을 통해
해당 데이터를 다른 트랜잭션이 접근할 수 있도록 허용 - ex) 어떤 트랜잭션이 어떤 Row를 Read하는 도중에
다른 트랜잭션이 해당 Row를
Read하는 것은 허용하지만
Write하는 것은 허용하지 않는
Shared Lock 사용 - ex) 어떤 트랜잭션이 어떤 Row를 Write하는 도중에
다른 트랜잭션이 해당 Row를
Read하는 것도 허용하지 않고
Write하는 것도 허용하지 않는
Exclusive Lock 사용 - 특정 Row가 Lock이 걸리면, 그 Row를 Unlock할 때까지
다른 트랜잭션은 해당 Row를 Lock할 수 없고, Unlock이 될 때 기다려야 함
→ 데드락 발생 가능성
- 특정 트랜잭션이 어떤 데이터를 Read 또는 Write를 시작하기 전에
데드락의 예시
- 트랜잭션 > 작업 > 연산
- X = Row X
- Y = Row Y
- T1 = 트랜잭션 1 = Read(Y) → Write(X)
- T2 = 트랜잭션 2 = Read(X) → Write(Y)
- Read(Y) = read_lock(Y) → read_item(Y) → unlock(Y)
- Write(X) = write_lock(X) → read_item(X) → X+=Y 계산 → write_item(X) → unlock(X)
- Read(X) = read_lock(X) → read_item(X) → unlock(X)
- Write(Y) = write_lock(Y) → read_item(Y) → Y+=X 계산 → write_item(Y) → unlock(Y)
- read_lock / read_item / write_lock / write_item / unlock = 연산(=Operation)
- 데드락은 여러 가지 잠금 규약(Locking Protocol)을 통해 해결 가능
트랜잭션 격리 수준
- 격리의 수준이 높을수록, 정합성은 높아지고 성능은 낮아짐.
1. READ_UNCOMMITED (Level 0)
- 트랜잭션 1을 시작한다.
- 트랜잭션 2를 시작한다.
- 트랜잭션 1이 ID = 1, VAL = 'MIN'인 데이터의 VAL을 KIM으로 변경했다.
- 트랜잭션 2가 ID = 1을 조회한다. VAL = 'KIM'이 조회되었다.
- 트랜잭션 1, 2가 종료된다.
- 정합성 Issue : Dirty Read
- UPDATE 반영 전에 읽는 오류
순서 5에서 오류가 생겨 롤백이 되었다고 가정하자. ID = 1은 다시 MIN 이 된다.
그러나 롤백 전인 순서 4번은 여전히 VAL = 'KIM' 으로 인식할 것이다. - INSERT 반영 전에 읽는 오류
트랜잭션 1이 특정 데이터를 INSERT한다.
트랜잭션 2가 그 데이터를 읽고 로직을 수행한다.
트랜잭션 1 수행 중 오류가 생겨 롤백된다. INSERT한 데이터가 삭제되었다.
그러나 트랜잭션 2는 이미 로직을 수행한 상태이다.
- UPDATE 반영 전에 읽는 오류
- 트랜잭션 1을 시작한다.
- 트랜잭션 1이 ID = 1인 데이터의 VALUE를 KIM으로 변경했다.
- 트랜잭션 2가 시작되었다.
- 트랜잭션 2가 ID = 1인 데이터를 조회한다. MIN이 검색된다.
- 트랜잭션 1이 커밋을 하고 종료한다.
- 트랜잭션 2가 ID = 1인 데이터를 조회한다. KIM이 검색된다.
- 트랜잭션 2가 커밋을 하고 종료한다.
- 정합성 Issue : Non-Repeatable Read
- 하나의 트랜잭션이 같은 값을 조회할 때, 다른 값이 검색되는 현상이다.
위의 그림에서 트랜잭션 2의 첫 번째 조회엔 MIN이, 두 번째 조회엔 KIM이 검색되고 있다.
- 하나의 트랜잭션이 같은 값을 조회할 때, 다른 값이 검색되는 현상이다.
- 트랜잭션 1을 시작한다.
- 트랜잭션 1이 ID = 1인 데이터를 조회한다.
- 트랜잭션 2가 시작되었다.
- 트랜잭션 2가 ID = 1인 데이터를 KIM으로 변경한다.
- 트랜잭션 1이 ID = 1인 데이터를 조회한다. 트랜잭션 2의 변경 내역이 보이지 않는다.
- 트랜잭션 2가 ID = 2인 데이터를 삽입 후 commit하여 트랜잭션을 종료한다.
- 트랜잭션 1이 ID = 2인 데이터를 조회한다. 데이터가 정상적으로 확인된다.
- 트랜잭션 1이 종료된다.
- UPDATE를 하려고 하면, UPDATE 하기 전 원본 데이터를 UNDO 영역에 백업해두고
- 실제 Table 상의 레코드 값을 변경하게 된다.
- 다른 트랜잭션들은 자신의 트랜잭션이 종료되기까지, UNDO 영역에 있는 원본 데이터를 접근한다
- 정합성 Issue : Phantom Read
- UPDATE 한 데이터에 대해서는 정합성을 보장하지만, INSERT/DELETE한 데이터는 정합성이 보장되지 않는다.
- 마치 유령을 보는 것처럼 있던 데이터가 사라지거나 없던 데이터가 생기는 현상을 말한다.
- 바로 위 예제의 순서 7에서 트랜잭션 1이 ID = 2인 데이터를 조회하고 있다.
만약 순서 6에서 트랜잭션 2가 비정상 종료되어 롤백되었다고 가정한다면
(2, 'KIM') 데이터는 삽입되지 않으며
트랜잭션 1은 ID = 2인 데이터를 읽을 수 없다.
4. SERIALIZABLE (Level 3)
- Read와 Write에 대하여 모두 Exclusive Lock을 수행
- 정합성 Issue 없음
- 가장 강력한 격리 / 가장 낮은 성능