x = 50 / y = 10
트랜잭션 1 : x가 y에 40을 이체
트랜잭션 2 : x에 30 입금
정상 동작 할 경우 : x = 40 / y = 50
- 순서
- 트랜잭션 2에서 read(x)로 읽을 때 lock을 취득
- 트랜잭션 1에서 read(x)로 읽을때 lock을 취득하며 읽으려 하나 트랜잭션 2에서 lock을 가지고 있어 대기
- 트랜잭션 2에서 x를 80으로 업데이트, write(x=80)
- 트랜잭션 2 완료 후 commit
- 트랜잭션 1에서 read(x) 작업 재개(lock 획득)
- read(x) => 80
- Locking Read 방식으로 인해 가장 최근의 commit된 data를 읽어옴
- 트랜잭션 1에서 x=40으로 업데이트(인출)
- 트랜잭션 1에서 y를 lock을 얻으며 읽음, read(y) => 10
- 트랜잭션 1에서 y를 50으로 설정, write(y=50)
- 트랜잭션 1을 commit
정상 결과, Lost Update 해결 x=40 / y= 50
MySQL LOST UPDATE 해결 : repatable read 만으로 해결이 안되고 locking read 추가 필요
Locking read : read를 하면서 Lock 취득 방식
트랜잭션 1: x와 y를 더해서 x에 쓴다.
트랜잭션 2 : x와 y를 더해서 y에 쓴다.
- 순서
- 트랜잭션 1에서 read(x)를 통해 lock을 얻고 값을 얻음
- 트랜잭션 2에서 x의 값을 얻으려 하지만 트랜잭션 1이 lock을 가지고 있어 대기
- 트랜잭션 1에서 read(y)를 통해 lock을 얻고 값을 얻음
- 트랜잭션 1에서 write(x)를 통해 값을 갱신
- 트랜잭션 1에서 결과 commit 후 lock 반환
- 트랜잭션 2에서 read(x)를 통해 갱신된 "20" 값 얻음
- 트랜잭션 2에서 read(y)를 통해 값 10을 얻음
- 트랜잭션 2에서 write(y=30)을 통해 갱신
- 트랜잭션 2 commit 후 lock 반환
Write Skew 문제 해결
트랜잭션 1: x와 y를 더해서 x에 쓴다.
트랜잭션 2 : x와 y를 더해서 y에 쓴다.
- 순서
- 트랜잭션 1에서 read(x)를 통해 lock을 얻고 값을 얻음
- 트랜잭션 2에서 x의 값을 얻으려 하지만 트랜잭션 1이 lock을 가지고 있어 대기
- 트랜잭션 1에서 read(y)를 통해 lock을 얻고 값을 얻음
- 트랜잭션 1에서 write(x)를 통해 값을 갱신
- 트랜잭션 1에서 결과 commit 후 lock 반환
- 트랜잭션 2에서 read(x)를 실행하나 실패 후 Rollback
- first-winner-update 적용
- 같은 data에 먼저 update한 Transaction이 commit되면 나중 Transaction은 Rollback
Rollback 이후 다시 트랜잭션을 실행여 Write Skew 문제 해결
트랜잭션 1: x와 y를 더해서 x에 쓴다.
트랜잭션 2 : x와 y를 더해서 y에 쓴다.
- 순서
- 트랜잭션 1에서 write(x)를 통해 lock을 얻고 값을 씀
- 트랜잭션 2에서 x의 값을 얻으려 하지만 트랜잭션 1이 lock을 가지고 있어 대기
- 중간 생략..
- 트랜잭션 2에서 read(x)를 실행하나 실패 후 Rollback
- first-winner-update 적용
- 같은 data에 먼저 update한 Transaction이 commit되면 나중 Transaction은 Rollback
Rollback 이후 다시 트랜잭션을 실행여 Write Skew 문제 해결
postgreSQL에서 FOR UPDATE, FOR SHARE : repeatable read 환경에서 동일하게 적용
MySQL은 rollback 없이 해결 가능, Postgre SQL은 rollback 이후 트랜잭션 다시 실행 후 해결
Read Skew 문제는 isolation 레벨 중 serializable 레벨로 해결할 수도 있음