At a Glance
Atomicity -> 전부 commit되거나 전부 rollback
Consistency -> 정의한 constraint와 invariant를 유효하게 유지
Isolation -> 동시 transaction의 중간 상태 노출을 통제
Durability -> commit된 결과를 장애 뒤에도 보존ACID는 애플리케이션의 모든 업무 규칙을 데이터베이스가 자동으로 알아서 지킨다는 뜻이 아닙니다. Constraint와 transaction 범위를 올바르게 설계해야 합니다.
작업 단위
아이템 구매에서 재화 차감과 아이템 추가가 하나의 업무 결과라면 같은 transaction으로 묶어야 한쪽만 반영되는 상태를 막을 수 있습니다.
WITH paid AS (
UPDATE wallets
SET gold = gold - 100
WHERE player_id = 42 AND gold >= 100
RETURNING player_id
)
INSERT INTO inventories(player_id, item_id)
SELECT player_id, 7 FROM paid;위 SQL을 transaction 안에서 실행한 뒤 application이 영향 row 수를 분기합니다.
await using var tx = await connection.BeginTransactionAsync();
purchaseCommand.Transaction = tx;
int insertedRows = await purchaseCommand.ExecuteNonQueryAsync();
if (insertedRows != 1)
{
await tx.RollbackAsync();
return false;
}
await tx.CommitAsync();
return true;영향받은 row가 0개면 재화 부족 또는 대상 없음이므로 transaction 전체를 rollback합니다. 외부 결제나 message broker까지 하나의 local DB transaction으로 자동 원자화되지는 않으므로 idempotency와 outbox·saga 같은 별도 경계가 필요할 수 있습니다.
Transaction 범위
Transaction을 오래 유지하면 lock과 old version이 오래 남아 다른 작업과 maintenance에 영향을 줄 수 있습니다. 사용자 입력이나 network 호출을 기다리는 동안 열린 transaction을 유지하지 않는 것이 기본입니다.
자주 틀리는 점
- Rollback이 이미 전송한 email이나 외부 API 호출을 되돌리지 않습니다.
- Consistency는 schema와 application이 정의한 규칙에 의존합니다.
- Auto-commit에서 SQL 두 개가 자동으로 같은 transaction이 되지 않을 수 있습니다.
- Commit 성공 응답을 잃은 경우 재시도 중복을 고려합니다.
참고 링크
2 sources