Transaction

· 3분 읽기

데이터베이스 트랜잭션은 여러 연산을 하나의 논리적 작업 단위로 묶어 데이터 일관성을 보장하는 핵심 메커니즘이다.

트랜잭션이 중요한 이유는 단순하다. 은행 계좌 이체를 생각해보면, A 계좌에서 출금은 성공했는데 B 계좌로 입금이 실패한다면 돈이 사라지는 심각한 문제가 발생한다.

당연히 실무에서도 밥 먹듯이 사용되고, 이런저런 사고의 원흉이 되기도 한다. 잘 알고 쓰는 것이 정말 중요하다.

ACID

ACID 는 데이터베이스 트랜잭션이 안전하게 수행되기 위해 보장해야하는 네 가지 속성의 약자이다.

Atomicity

원자성은 트랜잭션 내의 모든 연산이 전부 성공하거나 전부 실패해야 함을 의미한다. 부분적인 성공은 허용되지 않는다.

구현방식: Undo Log

  • 데이터 변경 전 값을 Undo Log 에 기록

  • 롤백 시 Undo Log 를 사용하여 이전 상태로 복원

  • 트랜잭션이 커밋되면 Undo Log 는 일정 시간 후 정리

BEGIN;
UPDATE accounts SET balance = balance - 10000 WHERE id = 1;  -- A 계좌 출금
UPDATE accounts SET balance = balance + 10000 WHERE id = 2;  -- B 계좌 입금
COMMIT;

만약 두 번째 UPDATE에서 오류가 발생하면:

  • 첫 번째 UPDATE도 롤백됨

  • Undo Log에 저장된 원래 balance 값으로 복원

  • 돈이 사라지거나 중복 생성되지 않음

Consistency

일관성은 트랜잭션 실행 전후로 데이터베이스가 일관된 상태를 유지해야 함을 의미한다.

솔직히 처음 봤을 때 너무 당연하게 들려서 오히려 기억 안난적도 많다.

근데 별 다른건 아니고, 모든 데이터 무결성 제약 조건들이 트랜잭션 후에도 만족되어야 한다는 뜻이다.

예를 들면 이런 것들:

  • NOT NULL: 필수 필드는 반드시 값이 있어야 함

  • UNIQUE: 중복된 값이 존재하면 안 됨

  • FOREIGN KEY: 참조 무결성 유지

  • CHECK: 특정 조건 만족 (예: age >= 0, balance >= 0)

Isolation

격리성은 동시에 실행되는 여러 트랜잭션이 서로 영향을 주지 않고 독립적으로 실행되는 것처럼 보여야 함을 의미한다.

완벽한 격리는 트랜잭션들이 순차적으로 실행된 것과 동일한 결과를 보장한다.

하지만 완벽한 격리는 성능 저하를 초래하므로, 실무에서는 다양한 격리 수준(Isolation Level)을 사용해 성능과 일관성 사이의 트레이드오프를 조절한다.

Durability

지속성은 트랜잭션이 성공적으로 커밋되면 시스템 장애가 발생해도 결과가 영구적으로 데이터베이스에 보존되어야 함을 의미한다.

WAL (Write-Ahead Log)

  1. 트랜잭션 시작

  2. 변경 내용을 WAL에 먼저 기록 (디스크에 fsync)

  3. 메모리의 Buffer Pool에 변경 내용 반영

  4. 백그라운드에서 주기적으로 데이터 파일에 반영 (Checkpoint)

이상 현상

동시성 제어가 불완전할 때 발생할 수 있는 이상현상들이 있다. 주로 세 가지가 유명하다.

Dirty Read

커밋되지 않은 데이터를 다른 트랜잭션이 읽는 현상이다. Read-Committed 이상에서는 기본적으로 방지 된다.

Non-Repeatable Read

같은 트랜잭션 내에서 동일한 행을 두 번 읽었는데 값이 달라지는 현상이다. 첫 번째 Read 와 두 번째 Read 사이에서 다른 트랜잭션이 Commit 되면서 값이 바뀌는 경우에 해당한다.

Repeatable Read 부터는 방지된다.

Phantom Read

같은 조건으로 조회했을때 없던 행이 생기는 현상이다. Non-Repeatable Read 와의 차이점은, Non-Repeatable Read 는 값이 달라지는 것이고, Phantom Read 는 없던 행이 생기는 현상이라는 점이다.

참고로 Phantom Read 는 Repeatable Read 에서도 발생할 수 있다. (MySQL InnoDB 는 Gap Lock 으로 방지)