ACID에서 I(Isolation)은 사실 100% 보장 되는 것이 아니라 그 level에 따라 정도가 달라진다. InnoDB는 SQL:1992 표준에 명시된 4가지의 Transaction Isolation Levels를 지원한다.
(1) READ UNCOMMITED
(2) READ COMMITED
(3) REPEATABLE READ (InnoDB 기본값)
(4) SERIALIZABLE
InnoDB는 각 level에 맞는 locking 전략을 써서 각 level을 지원한다. 각 level에 대해 알아보자. 이 각 레벨은 개별 트랜잭션의 입장에서 작업 대상에 대한 스스로의 고립성이 점점 강해지는 방향으로 존재한다고 이해하면 된다.
SELECT 문이 별도의 락을 거는 작업 없이 실행된다. 그래서 다른 트랜잭션(T2)에 의해 update되었고 아직 commit되지 않은 상태의 데이터를 읽어서 사용한다. 이때 T2에 의해 아직 commit 된 값이 아니기 때문에 굉장히 불안정한 데이터를 읽어서 사용하게 되며 이러한 문제를 Dirty Read라고 한다. 그냥 이름 그대로 READ UNCOMMITED (DATA)라고 생각하면 이해하기 편하다.
이것을 이해하기 전에는 일단 Consistent Read라는 개념에 대해 아는 것이 좋다. 이것은 SELECT 문이 실행될 때 특정 시점의 데이터베이스 스냅샷을 주는 multi-versioning을 의미한다. Consistent READ는 READ COMMITED / REPEATABLE READ 두 level에서 모두 발생하는데,
READ COMMITED인 경우에는 하나의 트랜잭션(T1)의 SELECT 문은 처음 당시의 스냅샷이 있었더라도 다른 트랜잭션(T2)의 커밋이 발생한다면 해당 커밋 이후의 스냅샷을 참조한다.
하지만 바로 밑에서 볼 REPEATABLE READ의 경우, 처음 SELECT를 했을 당시의 스냅샷이 T1의 트랜잭션 종료까지 그대로 유지된다.
READ COMMITED의 경우, 다른 트랜잭션에서 커밋까지 완료한 데이터의 경우 참조할 수 있다. 하지만 다른 트랜잭션(T2)에서 아예 새로운 row가 테이블에 추가되는 Phantom Row 문제가 있다.
InnoDB에서는 별다른 설정을 하지 않으면 REPEATABLE READ가 기본 level로 설정된다. 이 level에서는 하나의 트랜잭션 안의 SELECT 문들은 모두 항상 같은 스냅샷을 바라본다. 따라서 다른 트랜잭션이 row의 특정 컬럼 값을 갱신하거나 아예 새로운 row를 테이블에 추가하더라도 이것을 참조할 수 없다. 이 level은 하나의 트랜잭션 안에서는 REPEATABLE READ(반복적인 읽기)를 해도 늘 고립성이 유지되는, 늘 바라보는 스냅샷이 동일하다는 의미로 기억하면 외우기 쉬울 것이다.
가장 강력한 고립화 레벨로 REPEATABLE READ와 비슷하지만 한 가지 추가되는 부분이 있다. 즉, 모든 SELECT 문을 SELECT ... FOR SHARE 문으로 바꾸어 실행(autocommit 설정이 disabled 상태라면)한다는 특징이 있다. SELECT ... FOR SHARE와 같은 것을 Locking READ라고 하는데 읽을 row에 미리 shared lock을 걸고 읽는 것이다. 이렇게 되면 하나의 트랜잭션 안에서 안전하게 데이터를 조회하고 또 삽입/갱신하는 것이 가능해진다. 만약 이미 다른 lock이 걸려있는 상황이라면 Locking READ는 해당 lock이 풀릴 때까지 대기(blocking)하고 lock이 풀리면(release) 값을 읽는다. 신뢰도가 중요한 비지니스 상황에서는 이 level을 써야할 것이다.
InnoDB는 MVCC(Multi Version Concurrency Control)이라는 기술을 사용해서 락을 걸지않고 읽기 작업을 수행한다. 이를 Non-locking consistent read라고 하는데 SERIALIZABLE 레벨을 제외하고는 모두 이 기술이 쓰이고 있다. InnoDB는 Undo 로그를 이용해 이 기능을 구현한다. 여기서 멀티 버전은 하나의 레코드의 여러 버전이 동시에 관리된다는 뜻이다. READ_UNCOMMITED 레벨의 경우 데이터 버퍼나 디스크에 있는 내용을 읽고, 그 이상의 3가지 레벨들은 Undo 로그에 있는 값을 읽는 방식으로 단일 트랜잭션의 고립성을 유지하는 것이다.
그런데 사실 이렇게 글로만 보면 이해하기가 어려울 것이다. 각 level에 관한 실습을 진행하며 이해해보자.