격리 수준 (isolation level)
- 트랜잭션의 격리 수준이랑 여러 트랜잭션이 동시에 처리될 때 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있게 허용할지 말지를 결정하는 것이다.
- 격리 수준은 크게
READ UNCOMMITED
, READ COMMITED
, REPEATABLE READ
, SERIALIZABLE
의 4가지로 나뉜다.
- READ COMMITED는 거의 사용하지 않고 SERIALIZABLE 또한 동시성 문제 때문에 거의 사용되지 않는다.
- 데이터베이스의 격리 수준에 언급되는 세가지 문제점이 있다. 이는 레벨에 따라 발생할 수도 있고 아닐 수도 있다.
- 일반적으로 MySQL은 REPEATABLE READ, 이외 DBMS에서는 READ COMMITTED를 사용한다.
| DIRTY READ | NON-REPEATABLE READ | PHANTOM READ |
---|
READ UNCOMMITED | 발생 | 발생 | 발생 |
READ COMMITED | X | 발생 | 발생 |
REPEATABLE READ | X | X | 발생(InnoDB 예외) |
SERIALIZABLE | X | X | X |
1. READ UNCOMMITED
- READ UNCOMMITED 격리 수준에서는 트랜잭션에서의 변경 내용이 COMMIT이나 ROLLBACK 여부에 관계없이 다른 트랜잭션에서 보인다.
- 이러한 격리 수준의 문제는 COMMIT 되지 않은 불완전한 데이터를 가지고 로직을 수행한다는 점이다. (DIRTY READ)
2. READ COMMITED
- READ COMMITED 격리 수준은 오라클 DBMS의 기본 격리 수준이다.
- 해당 격리 수준에서는 특정 트랜잭션에서 COMMIT 되기 이전까지는 다른 트랜잭션에서 언두 로그 백업 데이터를 읽어 데이터의 일관성을 보장하려 한다.
- 하지만 위 상황처럼 사용자B에게 있어 트랜잭션 내의 같은 쿼리가 다른 결과를 낼 수 있는 부정합의 문제가 있다. (NON-REPEATABLE READ)
3. REAPEATABLE READ
- REPEATABLE READ는 MySQL의 기본 격리 수준이다.
- 해당 격리 수준에서 역시 언두 로그를 활용해 MVCC 방식을 사용하는데 READ COMMITED와 다르게 언두 영역의 여러 버전 중에 선택하는 방식이 다르다.
- 모든 트랜잭션에는 번호가 있으며 순차적으로 증가한다. 이를 이용해 자신의 트랜잭션 번호보다 작은 트랜잭션 번호에서 변경된 내용만 보도록 언두 로그를 선택한다.
- SELECT ... FOR UPDATE 쿼리는 예외로 SELECT하는 레코드에 쓰기 잠금을 걸어야 하는데, 언두 레코드에는 잠금을 걸 수 없기 때문에 현재 언두 영역이 아닌 현재상태의 레코드를 가져와야하는데 이 때문에 동일 트랜잭션 내에서도 해당 쿼리의 결과가 다를 수 있다. (PHANTOM READ, InnoDB 예외 : 갭락, 넥스트 키락 덕분에..)
4. SERIALIZABLE
- 해당 격리 수준에서는 select 쿼리 역시 공유 잠금(읽기 잠금)을 획득하며 동시에 다른 트랜잭션이 해당 레코드를 변경할 수 없다.
- 해당 격리 수준은 InnoDB의 메뉴얼에 나타나는 "Non-Locking consistent read" (잠금이 필요 없는 일관적 읽기)에 위배되고 동시성이 매우 떨어져 잘 쓰지 않는다.