home
트랜잭션 격리 수준
- 여러 트랜잭션이 동시에 처리될 때, 특정 트랜잭션이 다른 트랜잭션에서 변경한 데이터를 볼 수 있는지 여부를 결정
- 차례로 격리 수준이 엄격함
- Serializable
- Repeatable Read
- Read Committed
- Read Uncommitted
- 알고 가야하는 용어
Dirty Read
: 커밋되지 않은 데이터를 읽는 현상Non-Repeatable Read
: 같은 쿼리를 반복 실행했을 때 결과가 달라지는 현상Phantom Read
: 같은 쿼리를 반복 실행했을 때 이전에 없던 레코드가 나타나는 현상
Serializable
- 가장 엄격한 격리 수준
- 트랜잭션이 동시에 실행되는 것을 막음
- 각 트랜잭션이 순차적으로 실행된다.
- 네가지 중에서 성능이 가장 떨어짐 + 교착상태에도 빠지기 쉬움
- SELECT FOR UPDATE나 SHARE와 달리 순수 SELECT 작업도 레코드에 읽기 잠금을 한다.
Dirty Read
,Non-Repeatable Read
,Phantom Read
모두를 방지
Repeatable Read
- 트랜잭션 시작 시점의 데이터 스냅샷을 읽는다.
- MVCC(Multi-Version Concurrency Control)을 활용해서 한 트랜잭션 내에서 동일한 결과를 보장
- DB는 변경 전, 후의 데이터를 모두 저장해두는데 MVCC를 통해서 롤백이 가능
- 번호가 높은 트랜잭션이 커밋되었다고 해도, 번호가 낮은 트랜잭션보다 나중에 실행되었기 때문에 번호가 낮은 트랜잭션이 끝나지 않았다면 처음 트랜잭션 시작했을 때의 동일한 결과를 반환한다.
- 하지만 레코드가 생성될 때는 부정합이 생성될 수도 있다.
Phantom Read
가 발생할 수 있다는 건데 이는SELECT FOR UPDATE/SHARE
를 사용할 때 발생- 잠금이 있는 읽기는 언두 영역의 데이터가 아닌 테이블의 데이터를 읽게 되어서 문제 발생
| id | name | department | |----|-------|------------| | 1 | Alice | Sales | | 2 | Bob | Marketing |
- 이렇게 데이터가 있다고 했을 때, 트랜잭션 A는 다음과 같다고 가정하자.
-- Time 1: 트랜잭션 A 시작 START TRANSACTION; -- Time 2: Sales 부서의 직원 수를 조회 SELECT COUNT(*) FROM employee WHERE department = 'Sales'; -- 결과: 1 -- Time 5: 다시 Sales 부서의 직원 수를 조회 (FOR UPDATE 사용) SELECT COUNT(*) FROM employee WHERE department = 'Sales' FOR UPDATE; -- 결과: 2 (Phantom Read 발생) -- Time 6: 트랜잭션 A 종료 COMMIT;
- 트랜잭션 B는 다음과 같다고 가정하자.
-- Time 3: 트랜잭션 B 시작 START TRANSACTION; -- Time 4: 새로운 Sales 직원 추가 INSERT INTO employee (name, department) VALUES ('Charlie', 'Sales'); -- Time 5: 트랜잭션 B 종료 COMMIT;
- Repeatable Read 격리 수준에서 일반적인 SELECT 쿼리는 트랜잭션 시작 시점의 스냅샷(언두)을 읽기 때문에 일관성이 유지가 된다.
- 하지만 FOR UPDATE나 FOR SHARE와 같은 잠금이 있는 읽기 쿼리는 최신 데이터(테이블)의 데이터를 읽게 된다.
결과적으로, 같은 트랜잭션 내에서 실행된 두 쿼리가 서로 다른 결과를 반환하게 되어
Phantom Read
가 발생
- 하지만 Mysql은
SELECT FOR UPDATE
를 걸어놨을 시,갭락
을 통해서 다른 트랜잭션이 조회 조건에 해당하는 새 레코드를 삽입하는 것을 방지한다. Phantom Read
가 발생하는 경우는SELECT
이후의 트랜잭션에SELECT FOR UPDATE
를 걸어놨을 때 발생한다.
Read Committed
- 다른 트랜잭션의 커밋된 변경사항만 읽을 수 있다.
- 좋은 동시성을 제공하지만, 같은 쿼리를 반복실행할 때 결과가 달라질 수 있다.
- 같은 트랜잭션 내에서 다른 트랜잭션이 UPDATE를 했을 때, 처음 SELECT 결과는 언두의 데이터를 반환하게 된다.
- 하지만 다른 트랜잭션이 커밋을 하게 되면, 처음 SELECT 결과는 달리 최신 데이터를 반환하게 된다.
- 정교한 트랜잭션이 필요한 경우에는 적합하지 않다.
Dirty Read
는 방지되지만,Non-Repeatable Read
와Phantom Read
는 방지되지 않는다.
Read Uncommitted
- 다른 트랜잭션의 커밋되지 않은 변경사항을 읽을 수 있다.
- 최고의 동시성을 제공하지만 데이터 일관성이 매우 낮다.
- 실시간 데이터 모니터링, 캐시 업데이트 등에 적합
Dirty Read
,Non-Repeatable Read
,Phantom Read
모두 발생 가능- 다른 트랜잭션의 작업이 완료되지도 않았는데 다른 트랜잭션에서 이를 읽게되면 데이터 부정합 문제가 발생 ->
Dirty Read
- 다른 트랜잭션의 작업이 완료되지도 않았는데 다른 트랜잭션에서 이를 읽게되면 데이터 부정합 문제가 발생 ->
- 상당한 버그 발생 가능성이 있기 때문에 권장하지 않는다.