트랜잭션과 ACID 원칙

정처기 2026-07-18 23:39:52 정처기데이터베이스트랜잭션ACID

글 목록 →

계좌 이체를 생각해 보자. A 계좌에서 1만 원을 빼고, B 계좌에 1만 원을 더한다. 두 개의 UPDATE 문이다. 그런데 첫 번째 UPDATE가 끝난 직후 서버가 죽으면? 1만 원은 세상에서 사라진다.

이 문제를 막기 위해 DBMS는 “여러 연산을 하나의 논리적 작업 단위로 묶는” 장치를 제공한다. 그게 트랜잭션(Transaction) 이다.

트랜잭션이란

트랜잭션은 데이터베이스의 상태를 변화시키는 하나의 논리적 작업 단위다. 핵심은 “논리적”이라는 말이다. 물리적으로는 SQL 문 여러 개지만, 논리적으로는 쪼갤 수 없는 하나의 덩어리로 취급한다.

그래서 트랜잭션의 결과는 딱 두 가지뿐이다.

  • 전부 반영된다 (Commit)
  • 전부 취소된다 (Rollback)

“절반만 반영”은 존재하지 않는다. 이것이 트랜잭션의 존재 이유다.

트랜잭션의 상태

시험에 상태 전이가 종종 나온다. 5가지를 순서대로 기억하자.

상태설명
활동(Active)트랜잭션이 실행 중인 상태
부분 완료(Partially Committed)마지막 연산까지 실행했지만 아직 커밋 전
완료(Committed)커밋이 끝나 결과가 영구 반영된 상태
실패(Failed)오류로 더 이상 실행할 수 없는 상태
철회(Aborted)롤백되어 트랜잭션 이전 상태로 되돌아간 상태

흐름은 이렇다.

활동 ──> 부분 완료 ──> 완료
  │           │
  └──> 실패 <─┘

        └──> 철회 (Rollback)

주의할 점 하나. 부분 완료에서도 실패로 갈 수 있다. 마지막 연산까지 다 했어도 커밋 도중 디스크 오류가 나면 실패 상태로 떨어진다. “부분 완료 = 성공 확정”이 아니다.

ACID 4원칙

트랜잭션이 보장해야 할 네 가지 성질. 정처기 단골 문제다.

A — 원자성(Atomicity)

전부 수행되거나, 전혀 수행되지 않아야 한다. All or Nothing.

앞의 계좌 이체에서 출금만 되고 입금이 실패했다면, 출금도 되돌려야 한다. 이 되돌리기를 담당하는 것이 Rollback이고, 되돌릴 정보를 기록해 두는 것이 Undo 로그다.

C — 일관성(Consistency)

트랜잭션 전후로 데이터베이스가 일관된 상태를 유지해야 한다.

여기서 “일관”은 데이터베이스에 정의된 제약조건이 계속 만족된다는 뜻이다. 예를 들어 “계좌 잔액은 0 이상”이라는 제약이 있다면, 트랜잭션이 끝난 시점에도 그 제약은 지켜져야 한다. 이체 전 총액과 이체 후 총액이 같아야 한다는 것도 일관성의 예다.

원자성과 헷갈리기 쉬운데, 구분은 이렇다.

  • 원자성: 연산의 묶음에 대한 보장 (다 하거나 안 하거나)
  • 일관성: 데이터의 상태에 대한 보장 (규칙을 깨지 않는다)

I — 격리성(Isolation, 독립성)

둘 이상의 트랜잭션이 동시에 실행될 때, 서로의 중간 결과를 참조할 수 없다.

내 트랜잭션이 진행 중인 미완성 데이터를 남이 읽어 가면, 내가 롤백했을 때 남은 존재하지 않는 값으로 계산을 끝내 버린다. 이걸 막는 것이 격리성이고, 구현 수단이 잠금(Locking) 이다.

D — 지속성(Durability, 영속성)

성공적으로 완료된 트랜잭션의 결과는 영구적으로 반영되어야 한다.

커밋 응답을 받은 뒤라면, 그 직후 정전이 나도 데이터는 살아 있어야 한다. 이를 위해 DBMS는 변경 사항을 데이터 파일에 쓰기 전에 로그(Redo 로그)에 먼저 기록한다. 재시작할 때 로그를 보고 못다 쓴 변경을 다시 적용한다.

암기 팁: 원자성-Rollback, 지속성-Redo 로그, 격리성-Locking. 원칙과 구현 수단을 짝지어 외우면 응용 문제에서 흔들리지 않는다.

격리 수준과 이상 현상

격리성을 100% 지키면 안전하지만 느리다. 모든 트랜잭션을 한 줄로 세워야 하기 때문이다. 그래서 실무에서는 성능과 안전성을 저울질해 격리 수준(Isolation Level) 을 고른다.

먼저 격리가 약할 때 생기는 이상 현상 3가지부터.

현상내용
Dirty Read커밋되지 않은 값을 읽는다. 그 트랜잭션이 롤백하면 읽은 값은 유령이 된다
Non-Repeatable Read같은 행을 두 번 읽었는데 값이 다르다. 사이에 남이 UPDATE 했다
Phantom Read같은 조건으로 두 번 조회했는데 없던 행이 나타난다. 사이에 남이 INSERT 했다

Non-Repeatable Read와 Phantom Read의 차이는 행의 값이 바뀐 것(UPDATE)이냐, 행의 개수가 바뀐 것(INSERT)이냐다. 이 구분을 묻는 문제가 자주 나온다.

이제 격리 수준 4가지.

수준DirtyNon-RepeatablePhantom
Read Uncommitted발생발생발생
Read Committed방지발생발생
Repeatable Read방지방지발생
Serializable방지방지방지

아래로 갈수록 안전하고, 아래로 갈수록 느리다. 이 표는 통째로 외워 두면 객관식에서 바로 답이 보인다.

정리

  • 트랜잭션은 논리적 작업 단위이며, 결과는 커밋 아니면 롤백뿐이다.
  • 상태는 활동 → 부분 완료 → 완료, 갈라지면 실패 → 철회.
  • ACID: 원자성(All or Nothing), 일관성(제약조건 유지), 격리성(중간 결과 차단), 지속성(결과 영구 반영).
  • 격리 수준은 안전성과 성능의 트레이드오프이고, 낮을수록 Dirty / Non-Repeatable / Phantom Read가 순서대로 튀어나온다.

시험에서는 “다음 중 트랜잭션의 특성이 아닌 것은?” 같은 형태로 ACID를 직접 묻거나, 상황을 던져 놓고 “위반된 특성은?”을 묻는다. 네 원칙을 각각 한 문장으로 말할 수 있는지를 기준으로 점검해 보자.

댓글

이 글에 대한 의견은 아래 댓글로 남겨주세요 (GitHub 계정 필요). 로그인 없이 남기고 싶다면