DB 핵심 정리
🔐 CH 17 · TRANSACTIONS

여러 연산을 하나의 단위
안전하게 묶는 법 — 트랜잭션

ACID부터 스케줄(Schedule), Conflict Serializability와 선행 그래프(Precedence Graph), View Serializability, 복구 가능성, 격리 수준(Isolation Level)과 이상 현상까지 — 직접 스케줄을 짜고 그래프를 그려 직렬가능성을 판정하며 익히는 한국어 학습 자료입니다.

🧩 선행 그래프 시뮬레이터 🎬 트랜잭션 상태 머신 💸 스케줄 실행 추적기 📊 격리 수준 4×4 표

17.1 트랜잭션 개념 (Transaction Concept)

트랜잭션은 데이터베이스 시스템에서 일관성(consistency)신뢰성(reliability)을 보장하는 기본 단위다.

정의 (Definition)

트랜잭션
(Transaction)
여러 data item에 접근하고 갱신하는 하나의 프로그램 실행 단위(a unit of program execution).

트랜잭션이 다뤄야 할 두 가지 핵심 문제:

  • Failures — 하드웨어 고장·시스템 충돌 등 장애.
  • Concurrent execution — 여러 트랜잭션의 동시 실행.

예제: Fund Transfer (A → B, $50)

// T_i: A 계좌에서 B 계좌로 $50 이체
read(A);
A := A - 50;
write(A);
read(B);
B := B + 50;
write(B);

이 6개 연산은 "전부 반영되거나 전혀 반영되지 않아야" 하며, 도중에 A+B 합이 깨져 보여서도 안 된다.

ACID 요구사항 (Requirements)

위 이체 예제를 통해 왜 네 가지 보장이 필요한지 정리한다.

Atomicity (원자성)

트랜잭션의 부분 실행 결과가 DB에 반영되어서는 안 된다. write(A) 직후 장애가 나면 $50이 사라진 상태가 남으면 안 된다.

Durability (지속성)

트랜잭션 완료를 사용자에게 통보한 뒤에는, 이후 장애가 발생해도 그 갱신이 유지되어야 한다.

Consistency (일관성)

트랜잭션 전후로 A+B 합이 불변이어야 한다. explicit(예: 무결성 제약)·implicit 일관성 제약을 모두 보존.

Isolation (격리성)

다른 동시 트랜잭션이 부분 갱신된 DB에 접근하지 못해야 한다. serial 실행이면 자명하나, 성능 때문에 동시 실행이 필요하다.

💬 Consistency 예시

이체 전 상태 (A=900, B=300) → 이체 후 (A=850, B=350). 합 1200이 그대로 보존된다. 트랜잭션 도중에는 합이 1150처럼 보일 수 있으나, 이는 외부에 노출되어서는 안 된다(Isolation).


17.2 ACID 속성

트랜잭션이 보장해야 하는 네 가지 성질. 각 정의를 정확히 외우는 것이 핵심.

A Atomicity

All or Nothing. 트랜잭션의 모든 연산이 DB에 반영되거나, 전혀 반영되지 않거나 둘 중 하나다.

C Consistency

고립 실행(in isolation)되는 트랜잭션은 데이터베이스의 일관성을 보존한다.

I Isolation = Serializability

각 트랜잭션은 다른 동시 트랜잭션의 존재를 인지하지 못한다. 중간 결과(intermediate result)는 다른 트랜잭션에 숨겨진다.

D Durability

트랜잭션이 성공적으로 완료되면, 이후 시스템 장애가 발생해도 그 변경은 유지된다.

🎯 시험핵심 · ACID 정의

Atomicity = All or Nothing · Consistency = 고립 실행이 일관성 보존 · Isolation = Serializability(다른 TX를 인지 못함, 중간 결과 은닉) · Durability = 성공 후 장애에도 변경 유지. 특히 I = Serializability라는 점을 정확히.


17.3 트랜잭션 상태 (Transaction States)

트랜잭션은 실행되며 5개의 상태를 거친다. 정상 경로와 실패 경로를 구분하는 것이 핵심.

5개 상태

Active
초기 상태. 실행 중(executing)인 상태.
Partially
committed
마지막 명령(final statement)을 실행한 직후.
Failed
정상 진행이 불가능함을 발견한 후.
Aborted
롤백(rollback)을 마쳐 트랜잭션 이전 상태로 복원된 후 → 재시작(restart) 또는 폐기(kill).
Committed
성공적으로 완료(successful completion)된 후.

상태 전이 (Transitions)

  • active → partially committed → committed (정상 경로)
  • active → failed
  • partially committed → failed
  • failed → aborted

aborted 후에는 재시작하거나(restart) 그대로 종료(kill)한다.

인터랙티브: 트랜잭션 상태 머신

"재생 ▶"은 정상 경로를, "실패 경로"는 장애 경로를 애니메이션한다. 현재 상태가 강조 표시된다.

🎬 트랜잭션 상태 머신 인터랙티브
버튼을 눌러 상태 전이를 따라가 보세요.

17.4 스케줄 (Schedules)

동시 실행되는 트랜잭션들의 명령을 시간 순서로 나열한 것.

정의 & 규칙

Schedule
동시 실행 트랜잭션들의 명령에 대한 시간순 실행 순서(chronological order).
  • 모든 트랜잭션의 모든 명령을 포함해야 한다.
  • 각 트랜잭션 내부의 명령 순서는 보존되어야 한다.
  • 각 트랜잭션의 마지막 명령은 Commit(성공) 또는 Abort(실패).

예제 트랜잭션

T1
A에서 B로 $50 이체.
T2
A의 10%를 B로 이체.
  • Schedule 1: T1 다음 T2 (serial)
  • Schedule 2: T2 다음 T1 (serial)
  • Schedule 3: 인터리빙이지만 Schedule 1과 equivalent → serializable
  • Schedule 4: 인터리빙, A+B 보존 안 됨 → not serializable
💡 동시 실행을 하는 이유

활용도(utilization)↑ · 처리량(throughput)↑, 그리고 대기 시간(waiting time)↓ · 응답 시간(response time)↓. serial 실행은 안전하지만 자원 낭비가 크다.

인터랙티브: Schedule 3 vs Schedule 4 실행 추적

초기값 A=1000, B=2000. "다음 ▶"으로 한 연산씩 진행하며 A·B 값 변화를 추적한다. Schedule 3은 A+B를 보존하지만 Schedule 4는 깨뜨린다.

💸 스케줄 실행 추적기 인터랙티브

17.5 직렬가능성 (Serializability)

인터리빙된 스케줄이 어떤 serial 스케줄과 "동일한 효과"를 내면 직렬가능하다. 그 판정 기준이 conflict다.

Conflicting Instructions (충돌하는 명령)

서로 다른 트랜잭션 Tᵢ, Tⱼ가 같은 항목 Q에 접근하고 적어도 하나가 write이면 두 명령은 충돌한다.

Tᵢ의 명령Tⱼ의 명령충돌?의미
read(Q)read(Q)비충돌둘 다 읽기만 → 순서 무관
read(Q)write(Q)충돌읽은 값이 달라질 수 있음
write(Q)read(Q)충돌무엇을 읽는지 달라짐
write(Q)write(Q)충돌최종 값이 달라짐
🎯 시험핵심 · Conflict 4경우

같은 항목 Q에 둘 다 접근 & ≥1이 write면 conflict. R-R만 비충돌이고 R-W · W-R · W-W는 모두 충돌. 충돌하는 명령은 순서가 결과를 바꾸므로 순서가 강제되고, 비충돌 명령은 swap해도 결과가 동일하다.

Conflict Equivalent

스케줄 S를, 인접한 비충돌(non-conflicting) 명령들을 swap하는 연산만으로 S'로 변환할 수 있으면 S와 S'는 conflict equivalent하다.

Conflict Serializable

어떤 스케줄이 하나의 serial 스케줄과 conflict equivalent하면 그 스케줄은 conflict serializable하다.

🚫 not conflict serializable 예

T3: read(A) ; T4: write(A) ; T3: read(A) — T4의 write가 T3의 두 read 사이에 끼어, 어떤 swap으로도 serial 형태로 만들 수 없다.


17.6 선행 그래프 (Precedence Graph)

conflict serializability를 기계적으로 판정하는 도구. 정점=트랜잭션, 간선=충돌 순서.

작도 규칙 (Construction)

  • 정점(vertex) = 각 트랜잭션.
  • Tᵢ와 Tⱼ의 명령이 충돌하고 Tᵢ가 먼저 접근하면 간선 Tᵢ → Tⱼ를 그린다.
  • 간선에 충돌한 항목(item)을 라벨로 붙일 수 있다.

판정 (Test)

  • acyclic(비순환) ⟺ conflict serializable.
  • acyclic이면 topological sort로 직렬화 순서(serializability order)를 얻는다 (여러 개 가능).
  • cycle(순환)이 있으면 conflict serializable 아님. 예: T1↔T2 양방향 간선.
🎯 시험핵심 · 선행 그래프 정리

① 작도 규칙: 충돌하고 먼저 접근한 Tᵢ → Tⱼ. ② conflict serializable ⟺ precedence graph가 acyclic. ③ acyclic이면 topological sort가 직렬화 순서다(유일하지 않을 수 있음).

★ 선행 그래프 시뮬레이터 (Centerpiece)

프리셋을 고르거나 연산을 직접 추가/삭제해 스케줄을 만들면, 충돌을 분석해 선행 그래프(SVG)를 그리고 cycle을 검출해 직렬가능 여부와 직렬화 순서를 보여준다.

🧩 선행 그래프 시뮬레이터 인터랙티브
프리셋:

스케줄 (실행 순서)

선행 그래프


17.7 View Serializability 보충

conflict serializability보다 더 넓은 직렬가능성 개념. 읽은 값과 최종 값에만 주목한다.

View Equivalent — 세 조건

두 스케줄 S, S'가 다음 3조건을 모두 만족하면 view equivalent하다.

  1. ① Initial read 동일: S에서 Tᵢ가 Q의 초기값을 읽으면, S'에서도 Tᵢ가 Q의 초기값을 읽는다.
  2. ② Read-from(W→R) 보존: S에서 Tᵢ가 Tⱼ가 쓴 Q를 읽으면, S'에서도 Tᵢ는 Tⱼ가 쓴 Q를 읽는다.
  3. ③ Final write 동일: S에서 Q에 마지막으로 write한 트랜잭션은, S'에서도 Q에 마지막으로 write한다.

어떤 스케줄이 serial 스케줄과 view equivalent하면 view serializable하다.

포함 관계 & 성질

  • conflict serializable ⊆ view serializable (역은 성립하지 않음).
  • view serializability 판정은 NP-complete.
  • conflict는 아니지만 view serializable한 스케줄에는 항상 blind write(read 없이 write)가 존재.

예: T3: R(Q); T4: W(Q); T3: W(Q); T5: W(Q) — T4·T5의 W(Q)가 blind write.

포함 관계 다이어그램

📘 보충 · 동시성 ↔ 테스트 비용 트레이드오프

View(바깥 원): 더 많은 스케줄 허용 → 고동시성·고성능이지만 테스트가 어렵다(NP-complete). Conflict(안쪽 원): 더 엄격 → 저동시성·저성능이지만 테스트가 쉽다(선행 그래프 acyclic 검사). 실제 시스템은 검사 가능한 conflict serializability를 주로 사용한다.


17.8 복구 가능성 (Recoverability)

직렬가능성은 동시성의 정확성을, 복구 가능성은 장애 시 commit 순서의 정확성을 다룬다.

Recoverable

Tⱼ가 Tᵢ가 쓴 데이터를 읽었다면, Tᵢ의 commit이 Tⱼ의 commit보다 먼저 일어나는 스케줄.

Cascading Rollback

한 트랜잭션의 실패가 연쇄 롤백을 유발(T10 abort → T11, T12 롤백). recoverable하더라도 발생할 수 있어 바람직하지 않다.

Cascadeless

Tⱼ가 Tᵢ가 쓴 것을 읽으면 Tᵢ의 commit이 Tⱼ의 read보다 먼저. 모든 cascadeless ⊆ recoverable.

⚠ Non-recoverable 예 (Dirty Read)

T8: W(A) ; T9: R(A), T9 Commit ; 이후 T8 abort → T9는 이미 commit되어 되돌릴 수 없는데 존재하지 않을 값을 읽고 커밋했으므로 복구 불가. (T8이 T9보다 먼저 commit했어야 함.)

🎯 시험핵심 · recoverable / cascadeless

Recoverable: Tⱼ가 Tᵢ의 데이터를 읽으면 Tᵢ commit이 Tⱼ commit보다 먼저. Cascadeless: Tᵢ commit이 Tⱼ read보다 먼저. cascadeless ⊆ recoverable (cascadeless가 더 강한 조건).


17.9 격리 수준 (Isolation Levels)

완전한 serializability는 비싸므로, SQL은 약한 격리를 허용해 동시성을 높인다. 그 대가로 이상 현상(anomaly)이 나타난다.

4가지 이상 현상 (Anomalies)

Dirty Read

아직 commit되지 않은 쓰기 값을 읽음.

Nonrepeatable Read

같은 point query를 두 번 했는데 값이 다름.

Phantom Read

같은 range query를 두 번 했는데 새 레코드가 등장.

Serialization Anomaly

commit 결과가 어떤 직렬 순서와도 불일치.

👻 Phantom Phenomenon

tuple-level locking은 새로 삽입되는 튜플을 미리 잠글 수 없어 phantom read가 발생한다. 같은 범위를 다시 조회하면 다른 트랜잭션이 삽입한 새 레코드("유령")가 나타난다.

인터랙티브: 격리 수준 × 이상 현상 (4×4)

행(격리 수준)을 클릭하면 강조되고 설명이 표시된다. 약함 → 강함 순. 초록=Not Possible, 빨강=Allowed/Possible.

📊 격리 수준 4×4 표 인터랙티브
격리 수준 행을 클릭해 보세요.
🎯 시험핵심 · 격리 수준 4×4 표

Read uncommitted: Dirty Allowed, 나머지 Possible. Read committed: Dirty만 막음. Repeatable read: Dirty·Nonrepeatable 막지만 Phantom Allowed. Serializable: 전부 Not Possible. 강도순: Read uncommitted < Read committed < Repeatable read < Serializable.

각 수준 메모

Serializable
기본 격리 수준(SQL92 / SQLite). 모든 이상 현상 방지.
Repeatable read
MySQL 기본. 같은 레코드 재읽기는 동일하나 phantom 여지.
Read committed
commit된 값만 읽음. 재읽기 값은 달라질 수 있음.
Read uncommitted
commit 안 된 값도 읽음(가장 약함).

SQL 설정

-- 트랜잭션 종료
COMMIT WORK;
ROLLBACK WORK;

-- 격리 수준 설정
SET TRANSACTION ISOLATION LEVEL
     SERIALIZABLE;

JDBC에서 auto-commit 해제: setAutocommit(false). 이후 명시적 commit/rollback 필요.


17.10 직렬가능성 이론 심화 (Serializability Theory) 보충

"왜 acyclic이면 conflict serializable인가"를 증명 직관으로, 그리고 conflict / view / serializable의 엄밀한 포함 관계를 정리한다.

핵심 정리 (Theorem)

정리. 스케줄 S가 conflict serializable ⟺ S의 선행 그래프(precedence graph)가 acyclic이다.

아래는 엄밀한 형식 증명이 아니라, 시험에서 서술할 수 있는 증명 직관(proof sketch)이다.

① 충돌이 곧 간선 = "강제된 순서"

conflict serializable의 정의는 "인접한 비충돌 명령만 swap해서 어떤 serial 스케줄로 변환 가능"이다. 비충돌 명령은 swap해도 결과가 같으므로 자유롭게 옮길 수 있다. 반대로 충돌하는 두 명령은 순서를 바꾸면 결과가 달라지므로 상대 순서가 고정된다.

즉 Tᵢ가 Q에 먼저 접근하고 Tⱼ와 충돌하면, 어떤 동치 serial 스케줄에서도 Tᵢ가 Tⱼ보다 앞서야 한다. 이 "Tᵢ는 Tⱼ보다 먼저"라는 제약이 곧 간선 Tᵢ → Tⱼ다. 선행 그래프는 이런 강제 순서들의 집합이다.

② acyclic ⇒ serializable / cycle ⇒ 모순

(⇐) acyclic이면: 방향 그래프가 비순환이면 항상 위상 정렬(topological sort)이 존재한다. 모든 간선 Tᵢ→Tⱼ를 동시에 만족하는 트랜잭션 전순서를 얻을 수 있고, 그 순서대로 트랜잭션을 직렬 실행하면 모든 충돌 순서가 보존된다 → S와 conflict equivalent한 serial 스케줄이 존재 → conflict serializable.

(⇒) cycle이면: Tᵢ→Tⱼ→…→Tᵢ 처럼 순환이 있으면 "Tᵢ가 Tⱼ보다 먼저"이면서 동시에 "Tⱼ가 …를 거쳐 Tᵢ보다 먼저"여야 한다 — 전순서로 환원 불가능(모순). 어떤 직렬 순서로도 못 만든다 → conflict serializable 아님.

3-트랜잭션 예제: 작도 → cycle 판정 → 위상 정렬

스케줄 S = W₁(A) ; R₂(A) ; W₂(B) ; R₃(B) ; W₃(Q) (T1·T2·T3). 아래 선행 그래프 시뮬레이터의 "3-트랜잭션 예제" 프리셋과 동일하다.

1단계 · 충돌 작도

  • W₁(A) · R₂(A) → W-R 충돌, T1 먼저 ⇒ T1 → T2
  • W₂(B) · R₃(B) → W-R 충돌, T2 먼저 ⇒ T2 → T3
  • Q는 T3만 접근 → 간선 없음

2단계 · cycle 판정

간선은 T1 → T2 → T3 뿐. 되돌아오는 간선이 없으므로 acyclic. ⇒ conflict serializable 확정.

3단계 · 위상 정렬

선형 사슬이므로 직렬화 순서는 T1 ; T2 ; T3 하나로 유일하다. (간선이 더 적었다면 여러 순서가 가능 — 아래 콜아웃 참고.)

🎯 시험핵심 · acyclic ⟺ conflict serializable (증명 직관)

충돌 = 강제된 상대 순서 = 간선. acyclic이면 위상 정렬이 그 순서를 모두 만족하는 동치 serial 스케줄을 주고, cycle이면 "A보다 먼저이면서 A보다 나중"이라는 모순이라 어떤 직렬 순서로도 환원 불가. 그래서 두 명제가 동치다.

View Serializability 판정은 왜 NP-complete인가

blind write와 조합 폭발

conflict serializability는 선행 그래프 acyclic 검사로 다항 시간에 끝난다. 그러나 view serializability는 blind write(읽지 않고 바로 write) 때문에 final-write 조건을 만족시킬 후보 직렬 순서가 폭발적으로 늘어난다.

read-from / final-write 제약을 모두 만족하는 트랜잭션 순서를 찾는 문제는 polygraph(방향이 미확정인 간선 쌍 중 하나를 고르는 그래프)의 acyclic 방향 배정 문제로 환원되며, 이는 NP-complete로 알려져 있다.

엄밀 포함: conflict ⊊ view ⊊ serializable

  • conflict ⊊ view: 모든 conflict serializable은 view serializable. 역은 거짓 — blind write를 포함하는 view serializable 스케줄은 conflict serializable이 아닐 수 있다.
  • view ⊊ (모든 serializable): view serializable은 "결과가 어떤 serial과 같음"을 충돌·읽기·쓰기 구조로 포착하지만, 값 의미(semantics)까지 보는 더 넓은 직렬가능성은 포착하지 못한다.
  • 각 ⊊는 진부분집합(strict)임에 주의.

스케줄 분류 종합 다이어그램

직렬가능성(정확성 축)과 복구가능성(장애 복구 축)은 서로 직교(orthogonal)하는 별개의 축이다. 한 스케줄은 두 축의 위치를 독립적으로 가진다.

축 1 · 직렬가능성 (정확성)

Serial ⊊ Conflict-serializable ⊊ View-serializable ⊊ (모든 serializable 스케줄).

축 2 · 복구가능성 (장애 복구)

Strict ⊊ Cascadeless ⊊ Recoverable ⊊ (모든 스케줄). 다음 절에서 상세히.

📘 보충 · 두 축은 직교한다

직렬가능하지만 복구 불가능한 스케줄도, 복구 가능하지만 직렬가능하지 않은 스케줄도 존재한다. 실무 DBMS는 두 축을 모두 만족시켜야 한다 — 동시성 제어(직렬가능성) + 복구 관리(복구가능성).


17.11 복구가능성·연쇄롤백 심화 (Recovery Hierarchy) 보충

§17.8에서 다룬 recoverable / cascadeless를 strict까지 3단계 위계로 확장하고, 왜 DBMS가 strict를 선호하는지를 본다.

1 Recoverable (가장 약함)

Tⱼ가 Tᵢ가 쓴 데이터를 읽었다면, Tᵢ의 commit이 Tⱼ의 commit보다 먼저.

// recoverable (단, cascade 발생)
T8: W(A)
T9: R(A)        // 미커밋 값 읽음
T8: commit
T9: commit     // T8 이후 → OK

2 Cascadeless (연쇄롤백 없음)

Tⱼ는 Tᵢ가 commit한 뒤에만 Tᵢ가 쓴 값을 읽는다(Tᵢ commit이 Tⱼ read보다 먼저). 미커밋 값을 절대 안 읽으므로 연쇄 롤백 불가능.

// cascadeless
T8: W(A)
T8: commit
T9: R(A)        // 커밋된 값만 읽음
T9: commit

3 Strict (가장 강함)

Tᵢ가 쓴 데이터 항목은 Tᵢ가 commit/abort할 때까지 다른 TX가 read도 write도 못함. 미커밋 데이터에 대한 모든 접근을 차단한다.

// strict: W(A) 후 T8 종료까지
// 다른 TX는 A를 R/W 불가
T8: W(A)
T8: commit   // 이제부터 A 접근 허용
T9: R(A) / W(A)
🎯 시험핵심 · strict ⊊ cascadeless ⊊ recoverable

위계는 강함 → 약함 순으로 strict ⊊ cascadeless ⊊ recoverable. 더 강한 조건일수록 허용하는 스케줄이 적다. Recoverable=commit 순서만 강제(연쇄롤백은 허용). Cascadeless=미커밋 값 읽기 금지(연쇄롤백 차단). Strict=미커밋 값 읽기·쓰기 모두 금지.

위계 포함 다이어그램

왜 DBMS는 strict를 선호하는가

  • 복구가 단순하다. abort 시 그 TX가 쓴 값은 아무도 보지 못했으므로, before-image(이전 값)로 즉시 undo하면 끝 — 다른 TX 갱신을 추적·연쇄 롤백할 필요가 없다.
  • cascade 없음. cascadeless가 보장되므로 한 TX 실패가 다른 TX 롤백을 유발하지 않는다.
  • before-image 덮어쓰기 안전. 미커밋 write는 다른 TX가 안 읽으므로, 로그 기반 undo가 항상 올바른 복원값을 갖는다.
  • 대가: 항목을 commit까지 잠가 두므로 동시성은 다소 낮아진다. 대부분 상용 DBMS는 strict 2PL로 이 성질을 얻는다(Ch18).

17.12 실무 격리 수준과 이상현상 심화 (Anomalies in Practice) 보충

§17.9의 4×4 표를 구체 스케줄로 한 단계 더 파고, lost update·snapshot isolation·실제 DBMS 기본값을 본다.

이상 현상별 구체 스케줄

Dirty Read (미커밋 값 읽기)

T1: W(X)      // X=100→200 (미커밋)
T2: R(X)      // 200을 읽음 (dirty)
T1: abort   // X 200은 존재한 적 없음
T2: ... 200 기반 결정 → 오염

Read committed 이상에서 차단.

Non-repeatable Read (재읽기 불일치)

T1: R(X)      // X=100
T2: W(X), commit   // X=150
T1: R(X)      // 같은 행, 150 (달라짐!)

같은 point query 두 번 결과 상이. Repeatable read 이상에서 차단.

Phantom Read (유령 행)

T1: SELECT count(*) WHERE age>30  // 5
T2: INSERT (age=40), commit
T1: SELECT count(*) WHERE age>30  // 6!

같은 range query에 새 행 등장. tuple-lock으로 미삽입 행은 못 잠근다. Serializable(또는 범위 잠금)에서 차단.

Serialization Anomaly

// 각각은 commit됐지만 어떤
// 직렬 순서와도 결과 불일치
T1: R(A), W(B)
T2: R(B), W(A)
// T1→T2도 T2→T1도 결과와 안 맞음

선행 그래프에 cycle(T1↔T2). Serializable에서만 차단.

⚠ Lost Update (갱신 손실)

T1: R(X)=100 ; T2: R(X)=100 ; T1: W(X=120), commit ; T2: W(X=110), commit. 두 TX가 모두 stale한 100을 읽고 각자 갱신해 T1의 +20이 덮어써져 사라진다. (이는 본 장 §17.4 Schedule 4의 lost update와 같은 현상이다.) Read committed에서도 발생할 수 있어, 명시적 잠금(SELECT … FOR UPDATE)이나 더 높은 격리가 필요하다.

Snapshot Isolation 과 Write Skew 보충

Snapshot Isolation (SI) — forward reference

각 트랜잭션이 시작 시점의 일관된 스냅샷을 읽고, write는 자신의 버전에만 한다(MVCC). 읽기는 쓰기를 막지 않아 동시성이 높고, dirty/non-repeatable/phantom read를 대부분 막는다.

⤳ 자세한 메커니즘(버전·가시성·first-committer-wins)은 Ch18 동시성 제어에서 다룬다.

Write Skew — 격리수준 표의 한계

두 TX가 겹치지 않는 항목을 쓰지만 같은 불변식을 함께 위반하는 현상. 예: 의사 2명이 "최소 1명 당직" 규칙 아래 각자 자기 당직을 동시에 취소 → 둘 다 스냅샷상 "상대가 당직"이라 보고 commit → 0명 당직.

SI는 4가지 표준 anomaly를 막아도 write skew는 막지 못한다 — 그래서 §17.9 4×4 표(dirty/non-repeatable/phantom/serialization)만으로는 SI를 분류할 수 없다. Serializable Snapshot Isolation(SSI)이 이를 해결(Ch18).

실제 DBMS 기본 격리 수준

DBMS기본 격리 수준비고
PostgreSQLRead CommittedSERIALIZABLE 요청 시 SSI로 구현(write skew까지 방지). REPEATABLE READ는 사실상 SI.
MySQL (InnoDB)Repeatable Readnext-key lock으로 phantom을 상당 부분 방지(표준 RR보다 강함).
OracleRead CommittedSERIALIZABLE은 실제로는 Snapshot Isolation으로 구현(엄밀한 직렬가능성 아님 → write skew 가능).
SQL ServerRead Committed옵션으로 RCSI(스냅샷 기반 read committed)·SNAPSHOT 격리 지원.
SQL 표준Serializable표준이 규정하는 기본값이지만 실제 제품 기본값은 대부분 더 약함.
📘 보충 · 표준 ≠ 구현

SQL 표준의 격리 수준 정의는 "막아야 할 anomaly" 목록으로 되어 있어, 같은 이름이라도 제품마다 구현·강도가 다르다. 특히 여러 제품의 "SERIALIZABLE"이 실제로는 Snapshot Isolation이라 write skew가 통과할 수 있다는 점이 실무의 함정이다. 정확한 직렬가능성이 필요하면 제품이 그것을 진짜로 보장하는지 확인해야 한다.


17.13 핵심 정리 (Exam Cheatsheet)

시험 직전 한 번 더. 정의와 판정 규칙 위주로.

주제꼭 기억할 것핵심도
ACIDA=All or Nothing · C=일관성 보존 · I=Serializability · D=장애 후에도 유지.🎯 핵심
트랜잭션 상태active → partially committed → committed (정상). active/partially → failed → aborted.🎯 핵심
Schedule모든 명령 포함, TX 내부 순서 보존, 마지막=Commit/Abort.🎯 핵심
Conflict같은 Q & ≥1 write. R-R만 비충돌, R-W·W-R·W-W 충돌.🎯 최빈출
Precedence Graph먼저 접근한 Tᵢ→Tⱼ. conflict serializable ⟺ acyclic, topo sort=직렬화 순서.🎯 최빈출
View Serializable3조건(initial read·read-from·final write). conflict⊆view, 판정 NP-complete, blind write.보충
RecoverableTⱼ가 Tᵢ 데이터 읽으면 Tᵢ commit 먼저. cascadeless ⊆ recoverable.🎯 핵심
격리 수준RU<RC<RR<Serializable. 4×4 표 외우기(RR도 phantom 허용).🎯 최빈출
이론 증명 직관충돌=강제 순서=간선. acyclic→위상정렬=동치 serial, cycle→모순. view 판정 NP-complete, conflict⊊view⊊serializable.보충
복구 위계strict⊊cascadeless⊊recoverable. DBMS는 strict 선호(before-image로 즉시 undo, cascade 없음).보충
실무 격리lost update·write skew는 표 밖. SI는 4표준 anomaly만 차단. PG=RC, MySQL=RR, Oracle SERIALIZABLE=SI.보충
➡ 다음 장 예고 (Ch18)

이 장은 "무엇이 올바른가(serializability)"를 정의했다. Ch18은 그것을 어떻게 강제할지를 다룬다: Locking(S/X 락), Timestamps(read/write TS), Multiple versions(MVCC).