트랜잭션은 일련의 쿼리를 원자성있게 제공해준다.
원자성, 일관성, 영속성, 격리성
그중 격리성에 대해서 알아보자
낮은 격리성으로 발생가능한 현상
1. DirtyRead
: 만약 T1(Transaction 1)이 데이터를 수정했다. T2가 수정된 데이터를 읽어서 작업을 하는데, T1이 롤백이 되면 T2는 잘못된 데이터를 가져가는 것.
2. Non-Repeatable Read
: T1이 조회했고, T2가 업데이트 커밋, T1이 조회했을 경우 다른 값이 나온다.
3. Phantom
: T1이 조회했고, T2가 삽입/삭제, T1에 새로운 로우가 나타남.
DB 락
공유락 : 읽기만 가능
배타락 : 모두 불가능
격리성 수준
1. Read Uncommitted
: 커밋되지 않은 데이터를 읽을 수 있다. 즉 변경 가능성이 있는 데이터도 읽을 수 있는 것.
: 아무것도 막아주지 않는다.
: DirtyRead, Non-Repeatable Read, Phantom 발생 가능성이 있다.
2. Read Committed
: 커밋된 데이터만을 읽을 수 있다.
: 업데이트, 삽입/삭제는 막아주지 않는다.
: DirtyRead가 발생하지 않는다. 하지만 Non-Repeatable Read, Phantom이 발생한다.
3. Repeatable Read
: 두번 조회했을 때 결과값이 같은 것을 보장해준다.
: 업데이트는 막아주지만, 삽입/삭제는 막아주지 않는다.
: 하지만 삽입시 발생하는 Phantom은 보장해주지 않는다.
: 트랜잭션이 끝날 때까지 락을 걸어. 수정이 불가능하게 한다.
4. Serializable Read
: 모두 보장
다중버전동시성제어
: 스냅샵을 찍어둔다.
: 읽기와 쓰기를 분리.
: 스냅샷을 읽는 트랜잭션은 추가, 삭제, 업데이트를 무시한다.
개발과 연관해서 생각해보자.
: 현재 우리 시스템도 Read Committed를 사용한다.
: 데이터를 읽어오고 업데이트 시도 시 updDate가 변경되어 있으면 다시 읽어와 시도하는 DoTrasactionJob함수를 사용한다. 만약 3번이상 실패 시 트랜잭션 예외를 던진다.
: WAS환경에서 하나의 API에 동시 호출이 발생하면, 둘다 진입이 가능하게 된다. 그러므로 Redis Lock을 걸어준다.
: 최근 사건으로는 매칭로직에 두개 요청이 한번에 들어왔다. 매칭은 나와 제일 비슷한 팀을 매치를 해주는데. 전 경기에 해당되는 팀은 제거된다. 하지만 하나의 트랜잭션이 커밋이 되기전에 전경기를 조회하기 때문에 둘다 같은 팀이 매치되게 된다. 그래서 결국 셔플을 진행했다.
: 결국엔 크리티컬한 문제가 발생하면 락을 걸어주는게 맞는거다.
Mysql 트랜잭션 격리성 레벨 확인 쿼리
: show variables like 'tx%'