변수의 기록

(데이터베이스) 트랜잭션과 ACID 완전 정리 (Oracle 중심 + Java 예제 포함) 본문

CS지식/데이터베이스 (Database)

(데이터베이스) 트랜잭션과 ACID 완전 정리 (Oracle 중심 + Java 예제 포함)

불광동 물주먹 2025. 5. 19. 20:38

데이터베이스 트랜잭션과 ACID 완전 정리 (Oracle 중심 + Java 예제 포함)

트랜잭션(Transaction)이란?

트랜잭션은 하나의 논리적 작업 단위 (logical unit of work) 를 의미합니다.
일반적으로 여러 SQL 문장을 하나의 트랜잭션으로 묶어, 전부 성공하거나 전부 실패하게 만들어야 합니다.

예를 들어, 계좌이체는 출금과 입금이 동시에 성공하거나 동시에 실패해야 합니다.

핵심 특징

  • 트랜잭션에 포함된 SQL 일부만 실행되어 반영되는 일은 절대 없어야 합니다.
  • 데이터 정합성과 일관성을 유지하기 위해 필수적인 개념입니다.

Oracle의 트랜잭션 처리 방식

트랜잭션의 시작과 종료

Oracle에서는 INSERT, UPDATE, DELETE 같은 DML 문이 실행되면 트랜잭션이 자동으로 시작됩니다.

트랜잭션은 다음 중 하나로 종료됩니다:

  • COMMIT: 작업 내용을 데이터베이스에 영구 반영
  • ROLLBACK: 작업 내용을 모두 취소하고 이전 상태로 복원

오토커밋(AUTOCOMMIT)

  • SQL Developer, SQL*Plus 등의 클라이언트 도구는 기본적으로 오토커밋이 비활성화(OFF) 되어 있습니다.
  • JDBC(Java)는 기본적으로 오토커밋이 활성화(ON) 상태이므로, 명시적으로 꺼야 수동 트랜잭션 처리가 가능합니다.
 
-- SQL*Plus 등에서 오토커밋 비활성화
SET AUTOCOMMIT OFF;

트랜잭션 처리 흐름 (일반적인 절차)

  1. 트랜잭션 시작 (Oracle은 DML 실행 시 자동 시작)
  2. 비즈니스 로직 수행 (SELECT, INSERT, UPDATE, DELETE 등)
  3. 모든 과정이 성공하면 COMMIT
  4. 예외나 오류가 발생하면 ROLLBACK

Java(Spring Framework)에서의 트랜잭션 처리

@Service
public class AccountService {

    @Transactional
    public void transferMoney(Long fromId, Long toId, int amount) {
        accountRepository.decreaseBalance(fromId, amount);
        accountRepository.increaseBalance(toId, amount);
    }
}
  • @Transactional 어노테이션이 붙은 메서드는 트랜잭션 안에서 실행됩니다.
  • 예외가 발생하면 자동으로 rollback 되며, 기본적으로는 RuntimeException이 발생했을 때만 적용됩니다.
@Transactional(rollbackFor = Exception.class)  // 체크 예외까지 포함하려면 명시

트랜잭션의 핵심 속성: ACID

1. Atomicity (원자성)

  • 트랜잭션 내 작업은 모두 성공하거나 전부 실패해야 합니다.
  • 일부 작업만 반영되는 일은 없어야 하며, 실패 시 전체를 ROLLBACK 해야 합니다.

개발자가 할 일

  • 트랜잭션의 경계 명확히 설정
  • 예외 발생 시 적절하게 rollback 처리

DBMS가 보장하는 것

  • COMMIT 전까지는 실제 반영되지 않음
  • ROLLBACK 시 이전 상태로 되돌림

2. Consistency (일관성)

  • 트랜잭션 전후로 DB는 항상 일관된 상태(Consistent State) 를 유지해야 합니다.
  • 예를 들어 외래 키, 유니크 키 등의 제약 조건을 위반하면 안 됩니다.

Oracle이 보장하는 것

  • 제약 조건 위반 시 트랜잭션 실패

개발자가 챙겨야 할 것

  • 비즈니스 로직에서 도메인 모델이 불일치하지 않도록 설계
  • 예: 마감 후 입금, 이중 지급 등

3. Isolation (격리성)

  • 동시에 실행되는 여러 트랜잭션이 서로 간섭하지 않도록 보장해야 합니다.
  • 완전한 격리는 현실적으로 어렵기 때문에, 격리 수준(Isolation Level) 을 설정하여 trade-off를 선택합니다.

격리 수준 (Oracle 기준)


 

격리 수준 Dirty Read Non-repeatable  ReadPhantom Read 설명
READ COMMITTED 불가 발생 가능 발생 가능 Oracle 기본값, 커밋된 데이터만 읽음
SERIALIZABLE 불가 불가 불가 가장 엄격한 수준, 동시성 저하 가능
 
-- 격리 수준 설정 예시
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

4. Durability (지속성)

  • COMMIT된 트랜잭션은 시스템 장애가 발생하더라도 DB에 영구 반영되어야 합니다.
  • Redo log, 디스크 저장 등으로 보장됩니다.

Oracle의 보장

  • COMMIT 시 Redo log에 기록
  • DB 서버 다운 후 복구 시 Redo log를 이용하여 상태 복원

SAVEPOINT (중간 저장점)

하나의 트랜잭션 내에서 중간 저장 지점을 설정할 수 있습니다.
부분적인 작업만 롤백하고 이전 작업은 유지할 수 있습니다.

SAVEPOINT step1;

UPDATE users SET name = 'Kim' WHERE id = 1;

ROLLBACK TO step1;  -- 이후 작업만 취소

LOCK과 트랜잭션

동일 데이터를 동시에 여러 트랜잭션이 수정하려고 할 때 충돌을 방지하기 위해 Lock을 사용합니다.

  • SELECT ... FOR UPDATE: 해당 행을 다른 트랜잭션이 수정하지 못하도록 잠금
SELECT * FROM accounts WHERE user_id = 1 FOR UPDATE;

개발 시 트랜잭션 관련 체크리스트


항목 개발자 책임 DBMS 책임
커밋/롤백 시점 트랜잭션 경계 설정 트랜잭션 실행 및 로그 처리
일관성 유지 비즈니스 규칙 준수 제약 조건 검사
격리 수준 선택 트랜잭션 충돌 위험도에 따라 설정 동시성 제어 및 Lock 처리
지속성 보장 COMMIT 시점을 적절히 결정 로그 저장, 디스크 반영
 

마무리 요약

  • 트랜잭션은 데이터 정합성, 안정성, 신뢰성을 보장하는 핵심 개념입니다.
  • ACID 속성(원자성, 일관성, 격리성, 지속성)을 올바르게 이해하고 적용해야 합니다.
  • DBMS가 보장하는 기능뿐 아니라, 비즈니스 로직 측면에서의 트랜잭션 처리도 개발자가 적극적으로 설계해야 합니다.