Multi Version Concurrency Control
IsolationREAD_UNCOMMITED(level 1)READ_COMMITED(level 2)REPETABLE_READ(level 3) - mysql 기본SERIALIZABLE(level 4)
Isolation
- level이 올라갈수록 데이터 정합성이 더 보장이 되지만, 성능은 떨어질 수 있음. 동시성 저하. 일반적으로 READ_UNCOMMITED는 데이터 정합성 보장이 x, SERIALIZABLE은 성능 이슈가 있기에 그 사이 Isolation 단계를 많이 사용함
- DEFAULT(lEVEL 0)
READ_UNCOMMITED(level 1)
다른 Transaction의 commit 되지 않은 데이터도 읽음 → dirty read
- transaction 1 이 row를 update함
- transaction 2 가 해당 row를 읽음(transaction 1이 커밋되기 전에)
- transaction 1 이 롤백 시, transaction 2 는 존재하지도 않는 데이터를 읽게 됨
- 현재 Transaction에서 update를 하려고 할 시 다른 Transaction이 commit이 될 때까지 lock이 걸리게 됨
READ_COMMITED(level 2)
커밋이 완료된 데이터만 다른 트랜잭션에서 조회 가능함 → Unrepetable Read
발생 가능
- transaction 1 에서 row를 읽음
- transaction 2 에서 row를 수정하고 커밋함
- transaction 1 에서 row를 다시 읽음 →
Unrepeatable read
발생 (transaction 2 에서 변경한 값을 읽게 됨)
REPETABLE_READ(level 3) - mysql 기본
InnoDB 스토리지 엔진에서는 트랜잭션이 Rollback 될 가능성에 대비해 변경되기 전 레코드를 Undo
영역에 백업해두고 실제 레코드 값을 변경함 ( MVCC
— Multi Version Concurrency Control )
MVCC
: DBMS에서 쓰기 세션이 읽기 세션을 블로킹하지 않고, 읽기 세션이 쓰기 세션을 블로킹하지 않게 서로 다른 세션이 동일한 데이터에 접근했을 때 각 세션마다 스냅샷 이미지 보장해주는 메커니즘
Undo
영역 : UPDATE, DELETE 로 인해 데이터 변경 시, 변경되기 전의 데이터를 보관하는 곳 (롤백 대비용, 격리 수준 유지용)
- 트랜잭션 별로 Undo 영역에 백업 데이터를 만들어 두기 때문에(Snapshot) 동시에 여러 Transaction 이 진행되어 백업 레코드가 많아질수록 MySQL 서버 처리성능 떨어질 수 있음
- Transaction이 시작할 때 snapshot을 가지고 있고 거기서 부터 값을 읽음
- 기존에 존재하는 데이터는 Undo 영역에 존재할 수 있지만 새로 추가된 데이터는 Undo 영역에 존재할 수가 없음 ⇒
Undo
영역의 snapshot을 가지고 시작하여도, 새로 추가된 데이터에 대해서는 조회가 되는 것임 (Phantom Read
) — 추측
Phantom Read
- transaction 1 에서 특정 기준을 충족하는 row를 조회
- SELECT … FOR UPDATE 쿼리는 SELECT 하는 레코드에 쓰기 잠금을 적용해야 하는데, Undo 레코드에는 잠금을 걸 수 없으므로, 현재 레코드의 값을 가져오게 됨
- transaction 2 에서 해당 기준을 충족하는 row를 추가
- transaction 1 에서 동일한 기준으로 row 조회 시, row 개수가 달라짐
@Modifying @Query(value= "update book set category='update'", nativeQuery=true) // repository로 update시에는 // select 후 update를 하기에 phantom read 현상 나타내기 힘들어서 nativeQuery사용 void update();
SERIALIZABLE(level 4)
- 다른쪽에서 데이터를 수정하는 Transaction이 시작되면 현재 Transaction은 그냥 걔가 끝날 때까지 무조건 기다림(락이 걸림)