Transaction

3줄 요약

  • Transaction은 여러 DB 작업을 하나의 성공 또는 실패 단위로 묶어 데이터 정합성을 지키는 경계다.
  • 백엔드에서는 트랜잭션 경계가 API 경계, 서비스 메서드, 외부 API 호출, 메시지 발행, 락 보유 시간과 직접 연결된다.
  • 좋은 트랜잭션 설계는 짧고 명확하며, 실패 시 재시도와 보상, 멱등성, 롤백 기준을 설명할 수 있어야 한다.

핵심 정리

  • ACID는 원자성, 일관성, 격리성, 지속성을 뜻하지만 실제 보장 수준은 DB 엔진, 격리 수준, 쿼리 방식, 애플리케이션 경계에 따라 달라진다.
  • 트랜잭션은 DB 커넥션에 묶인다. Spring에서 @Transactional은 같은 스레드의 트랜잭션 동기화와 커넥션 사용 흐름을 관리한다.
  • 트랜잭션이 길어지면 락 보유 시간이 늘고, 커넥션을 오래 점유하며, MVCC 기반 DB에서는 오래된 row version 정리를 방해할 수 있다.
  • 외부 API 호출을 트랜잭션 안에 넣으면 DB 락과 커넥션이 외부 시스템 응답 시간에 묶인다. 결제, 알림, 파일 업로드는 경계 설계가 특히 중요하다.
  • 롤백은 만능이 아니다. DB 안의 변경은 되돌릴 수 있어도 외부 시스템 호출, 메시지 발행, 이메일 전송은 별도 보상이나 outbox 패턴이 필요할 수 있다.
  • 재시도는 멱등성과 함께 설계해야 한다. 데드락, 일시적 네트워크 오류, serialization failure는 재시도 후보지만, 중복 주문이나 중복 포인트 적립을 막는 키가 필요하다.
  • Spring의 기본 롤백 규칙, proxy 적용 범위, self-invocation, propagation은 실제 커밋/롤백 결과를 바꾼다. @Transactional을 붙였다는 사실보다 실제 proxy를 통과하는 호출인지, 어떤 예외가 밖으로 전파되는지 확인해야 한다.
  • 읽기 트랜잭션도 운영 자원이다. readOnly=true는 의도와 일부 최적화 힌트가 될 수 있지만, 긴 streaming 조회나 느린 select는 여전히 커넥션과 snapshot을 오래 붙잡는다.

헷갈리는 지점

  • @Transactional을 붙이면 모든 정합성 문제가 해결된다고 생각하기 쉽다. 선언 하나로 롤백이 되는 모습이 강력해 보이기 때문이다.
    • 핵심은 트랜잭션이 DB 경계 안의 작업을 묶을 뿐 외부 부작용까지 자동으로 되돌리지 않는다는 점이다.
    • 격리 수준, 락, 재시도, 멱등성은 별도로 설계해야 한다.
  • 트랜잭션은 길수록 안전하다고 오해하기 쉽다. 많은 작업을 한 번에 묶으면 일관성이 좋아 보이기 때문이다.
    • 핵심은 긴 트랜잭션이 락과 커넥션을 오래 잡아 장애를 키운다는 점이다.
    • 일관성 단위를 정확히 잡고 외부 I/O는 분리하는 편이 좋다.
  • 읽기 전용 API에는 트랜잭션이 필요 없다고 생각하기 쉽다. 데이터를 변경하지 않기 때문이다.
    • 핵심은 일관된 읽기, Lazy Loading, 커넥션 관리, Hibernate flush mode와 관련이 있다는 점이다.
    • 읽기 전용 트랜잭션은 의도 표시와 최적화 힌트로도 의미가 있다.
  • Spring에서 예외가 나면 항상 롤백된다고 생각하기 쉽다. 대부분의 예제는 RuntimeException만 보여주기 때문이다.
    • 핵심은 기본적으로 unchecked exception 중심으로 롤백되며, checked exception, 예외 삼키기, 내부 호출, noRollbackFor 설정에 따라 결과가 달라질 수 있다는 점이다.
    • 중요한 변경 작업은 통합 테스트에서 실제 commit/rollback 결과를 확인해야 한다.

확인 질문

  • 트랜잭션 경계를 설계할 때 가장 먼저 정해야 하는 것은 무엇인가?
    • 어떤 데이터 변경들이 하나의 비즈니스 성공 또는 실패 단위인지 정해야 한다.
  • 외부 API 호출을 트랜잭션 안에 넣는 것이 위험한 이유는 무엇인가?
    • 외부 응답 지연 동안 DB 커넥션과 락을 오래 잡아 전체 서비스 지연과 락 경합을 키울 수 있기 때문이다.
  • 재시도를 안전하게 만들기 위해 필요한 것은 무엇인가?
    • 멱등 키, Unique 제약, 상태 전이 규칙, 중복 처리 정책, 재시도 가능한 오류와 불가능한 오류의 구분이다.
  • 트랜잭션이 길어졌는지 운영에서 의심할 수 있는 신호는 무엇인가?
    • pool pending 증가, connection acquire time 증가, lock wait, long transaction, idle in transaction, vacuum 지연, replica lag, p99 지연 증가다.