MultiVersion Concurrency control
데이터 베이스 lock : read - read일 경우에만 지연없이 처리가 가능하다.
한 트랜잭션이 write lock 획득 시 다른 트랜잭션은 read/write 둘다 불가능하다.
서로 같은 데이터에 대해서 서로 다른 트랜잭션이 write - write인 경우에만 처리가 불가능하고 write lock 취득 후 다른 트랜잭션은 read가 가능하다.
MVCC 는 commit 된 데이터만 읽는다. 최소 isolation level이 read committed이다.
한 트랜잭션이 commit 후 unlock을 시도한다. recoverability를 위해 commit할 때 write lock을 unlock 한다.
트랜잭션 1의 isolation level이 read committed인 경우 커밋된 값만 읽기 때문에 x는 50이다. (MySQL, PostgreSQL)
isolation level이 repeatable read인 경우 트랜잭션의 시작 시간을 기준으로 시작 전 최근 commit된 데이터를 읽기 때문에 트랜잭션2가 x의 값을 바꾸기 전인 10을 읽는다. (MySQL, PostgreSQL)
MVCC 는 데이터를 읽을 때 특정 시점 기준으로 가장 최근에 commit된 데이터를 읽는다. 특정 시점은 isolation level에 따라 다르다.
Consistent read : 특정 시점을 기준으로 데이터를 read한다.
트랜잭션2는 x가 50일때 트랜잭션1이 write lock을 가지고 있어도 read가 가능하기 때문에 x의 값을 읽는다. 그 후 30을 추가하는 write는 불가능하다.
트랜잭션 1이 commit하고 write lock을 반납 후 트랜잭션 2는 write를 시작한다.
결과값이 x= 80, y = 50. Lost Update가 발생한다. 업데이트 된 정보가 사라진다.
PostgreSQL인 경우에는 같은 데이터에 대해서 트랜잭션들이 write할 경우
먼저 update를 실행한 트랜잭션이 commit하면 나중에 update한 트랜잭션은 롤백된다. (first-updater-win)
트랜잭션마다 서로 다른 isolation level을 설정할 수 있다.
트랜잭션2가 먼저 시작하고 트랜잭션1이 나중에 시작할 경우. 트랜잭션1은 write를 수행하지 못하고 lock을 획득할 때 까지 기다렸다가 트랜잭션 2가 lock 반환시점에 write를 하게된다. 트랜잭션2 결과 x = 80 이지만, 트랜잭션1의 결과 x=10이다. (Lost Update 발생)
트랜잭션 1이 repeatable read인 경우 나중에 update를 진행하기 때문에 rollback이 된다.
즉, 데이터의 정합성이 충족시키려면 하나의 트랜잭션의 isolation level만 신경쓰는것이 아니라, 모든 트랜잭션의 level을 관리해주어야한다.
MySQL의 경우 나중에 update하는 트랜잭션이 rollback이 일어나지 않아 그대로 commit해버리고, Lost Update가 발생한다.
MySQL에서는 repeatable read만으로 Lost Update를 해결할 수가 없다. 따라서 Locking read를 사용한다.
select ... for update; 개발자가 직접 for update 문을 작성해야한다.
트랜잭션2는 x를 read할 때 write lock을 획득하고, 트랜잭션1도 그냥 read하는것이 아닌, locking read로 실행하고 write lock을 획득해야한다.
트랜잭션1의 시작 시점인 x의 값 50을 읽는것이 아니라, MySQL에서 locking read는 가장 최근 commit된 데이터를 읽는다. (x=80)
locking read는 read할 때 write lock을 획득한다. 그 후 데이터를 읽을때에는 가장 최근 commit시점에서의 데이터를 읽는다.
WRITE SKEW 발생 : 트랜잭션을 시작할 때의 데이터 내용과 트랜잭션이 끝나기 전의 데이터가 다르다. 20/30 또는 30/20이 출력되어야 하지만, 20/20인 상태
트랜잭션1은 read할 때 write lock을 획득하고, locking read이기 때문에 트랜잭션2는 x에 대한 데이터를 read하기 위해서는 트랜잭션1이 write lock을 반환할때 까지 대기해야한다.
트랜잭션1이 lock 반환 후 트랜잭션2는 x에 대해 read를 진행
값이 정확하게 나온다. Write skew 해결 즉, Write skew를 해결하기 위해서 locking read를 사용해야한다.
PostgreSQL의 경우 locking read를 사용하면 나중에 update하는 트랜잭션은 rollback이 된다.