MVCC(multiversion concurrency control)
MVCC
x = 50 / y = 10
트랜잭션 1 : x가 y에 40을 이체
트랜잭션 2 : x에 30 입금
Postgre SQL은 snapshot 방식으로 MVCC 동작
- 정상 동작 할 경우 : x = 40 / y = 50
- 트랜잭션 1, 2 모두 Read Committed로 가정
- 트랜잭션 1이 먼저 실행된다 가정
- 순서
- 트랜잭션 1에서 read(x) => 50
- 트랜잭션 1의 snapshot에서 x=10으로 작성 write(x=10)
- 트랜잭션 2에서 x를 읽기, read(x) => 50
- 트랜잭션 2에서 30입금 -> write(x=80) -> 트랜잭션1에서 write lock을 가지고 있어 대기
- 트랜잭션 1에서 read(y) => 10
- 트랜잭션 1에서 snapshot에 write(y=50)
- commit(snapshot 반영) (x->10 / y -> 50)
- 트랜잭션 2에서 x에 대한 lock 획득 후 snapshot에 x갱신, write(x=80)
- 트랜잭션 2 commit (x->80)
Lost Update 발생(x에서 40을 빼는 update 무시)
해결 : 트랜잭션2의 Isolation level을 Repeatable Read로 변경
- Postgre SQL에서 Repeatable Read의 특성은 first-updater-win의 특징을 기짐
- first-updater-win : 같은 data에 먼저 update된 Transaction이 commit되면 나중 Transaction은 rollback
- 위 과정에서 8번 부분에서 write(x=80)이 실패함
- first-updater-win 적용되어 x값이 이미 commit이 되었기 때문
- 이후 롤백되어 최종 결과는 x=10, y=50이 되고, 다시 트랜잭션2를 실행하면 정상적인 결과를 얻을 수 있음
x = 50 / y = 10
트랜잭션 1 : x가 y에 40을 이체
트랜잭션 2 : x에 30 입금
Postgre SQL은 snapshot 방식으로 MVCC 동작
- 정상 동작 할 경우 : x = 40 / y = 50
- 트랜잭션 1은 Read Committed / 트랜잭션 2는 Repeatable Read 설정
- 트랜잭션 2가 먼저 실행된다 가정
- 순서
- 트랜잭션 2가 먼저 x를 읽는다, read(x) => 50
- 트랜잭션 1이 x를 읽는다, read(x) => 50
- 트랜잭션 2가 x값을 갱신한다. write(x=80) / lock획득
- 트랜잭션 1이 x값을 갱신한다. write(x=10) -> lock이 없어 대기
- 트랜잭션 2가 commit 후 lock 반환(DB x = 80 갱신)
- 트랜잭션 1이 못했던 4번을 실행. write(x=10)
- 트랜잭션 1이 y를 읽는다. read(y) => 10
- 트랜잭션 1이 y값 갱신. write(y=50) => lock획득
- 트랜잭션 1이 commit하여 DB 갱신(x = 10, y = 50)
**Lost Update 발생(트랜잭션 2의 x 갱신 update)
해결 : Transaction 1의 Isolation Level을 Repeatable Read로 변경
- 위 과정에서 6번을 수행할 때 rollback 발생
- first-updater-win 속성 때문
- 따라서 최종 결과는 x=80, y=10으로 트랜잭션 1을 다시 실행 시 정상적인 결과를 얻을 수 있음
LOST UPDATE : MVCC로 진행하다 LOCK에 의해 업데이트가 반영 안된 것
트랙잭션마다 서로 다른 isolation level 줄 수 있음
한 트랜잭션의 Isolation level만 챙기는 것이 아니라 양쪽 모두 신경 써야함
MySQL에서는 같은 데이터에 먼저 update한 트랜잭션이 커밋하게되면 나중 트랜잭션은 롤백되는 경우가 없음
MySQL에서 해결방법은 2부에