ACID의 'I'가 실제로 보장하는 것과 보장하지 않는 것
"Isolation"이라는 단어가 주는 착각
ACID를 처음 배울 때 원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 지속성(Durability)을 네 개의 대등한 보장처럼 배웁니다. 그런데 앞의 세 글자와 마지막 글자는 성격이 다릅니다. 원자성과 지속성은 켜져 있거나 꺼져 있거나 둘 중 하나입니다. 트랜잭션은 전부 반영되거나 전혀 반영되지 않고(원자성), 커밋된 데이터는 정전이 나도 사라지지 않습니다(지속성). 이건 협상의 여지가 없는 값입니다.
격리성은 다릅니다. 격리성에는 정도가 있습니다. PostgreSQL 공식 문서조차 이렇게 말합니다 — "SQL 표준은 이상적인 직렬화 가능(serializable) 실행을 정의하지만, 실제로는 그 이상에 얼마나 가깝게 근사할지를 격리수준이라는 이름으로 선택하게 한다." 즉 ACID의 'I'는 하나의 약속이 아니라 네 단계짜리 메뉴입니다. 이 사실을 모르고 있으면 "우리 DB는 트랜잭션을 지원하니까 동시성 문제는 없다"는 잘못된 결론에 도달하기 쉽습니다.
완전한 격리의 비용
이론적으로 가장 안전한 방법은 간단합니다. 트랜잭션을 한 번에 하나씩만 실행하면 됩니다. 그러면 Lost Update도, Dirty Read도, 그 무엇도 일어날 수 없습니다. 문제는 이러면 동시성이 0이 된다는 겁니다. 사용자 100명이 접속한 서비스에서 트랜잭션을 줄 세워 하나씩 처리하면 서비스는 멈춘 것처럼 느껴질 겁니다.
그래서 모든 실무 DB는 타협합니다 — "완벽하게 격리된 것처럼 보이되, 실제로는 동시에 실행해서 성능을 챙긴다." 이 타협을 구현하는 두 가지 전략이 있습니다.
flowchart LR A["트랜잭션 격리 구현 전략"] --> B["비관적 락킹\n실제로 순서를 강제한다"] A --> C["MVCC\n각자 다른 버전을 보여줘서\n순서를 강제한 것처럼 보이게 한다"] B --> D["2PL, SELECT ... FOR UPDATE"] C --> E["PostgreSQL, Oracle,\nMySQL InnoDB의 기본 동작"]
두 전략 모두 5~6장에서 자세히 다룹니다. 지금 기억할 것은 하나입니다 — 격리수준은 DB가 지켜주는 약속의 이름이지, 물리적으로 순서대로 실행된다는 뜻이 아닙니다. Serializable조차도 대부분의 구현에서 실제로는 병렬로 실행한 뒤, 직렬 실행과 같은 결과가 나오지 않으면 한쪽을 실패시키는 방식으로 동작합니다(5장, 8장에서 SSI로 다시 다룹니다).
일관성(Consistency)과의 혼동
한 가지 자주 나오는 혼동을 짚고 넘어가겠습니다. ACID의 'C'(Consistency)와 CAP 정리의 'C'(Consistency)는 다른 개념입니다. ACID의 일관성은 "제약조건(FK, CHECK, UNIQUE)을 위반하는 상태로 커밋되지 않는다"는 뜻이고, 이건 애플리케이션과 DB 스키마가 함께 책임집니다. 반면 이 책에서 다루는 격리성은 "동시에 실행된 트랜잭션들이 서로의 중간 상태를 얼마나 볼 수 있는가"의 문제입니다. 면접에서 이 둘을 섞어 설명하면 바로 티가 납니다 — 저도 처음엔 헷갈렸습니다.
정리하면, 격리성은 이진값이 아니라 스펙트럼이고, 그 스펙트럼의 이름이 격리수준입니다. 다음 장에서는 이 스펙트럼의 각 지점에서 정확히 무엇이 새고 무엇이 막히는지, 이상현상 네 가지를 하나씩 재현하며 살펴보겠습니다.