본문 바로가기
DB

트랜잭션의 전파 방식

by 고선제 2023. 10. 24.

목차

  1. 트랜잭션 전파란?
  2. 트랜잭션 전파 순서
  3. 트랜잭션 전파 속성

1. 트랜잭션의 전파란?

  • 트랜잭션 전파
    • 하나의 트랜잭션 내부에 다른 트랜잭션이 있는 경우, 트랜잭션 정책에 따라 어떻게 동작할 지 결정하는 것이다.
  • 트랜잭션 내부에 트랜잭션이 존재하는 경우, 트랜잭션 전파 수준에 따라 트랜잭션을 새로 만들 수도 있고, rollback범위도 달라진다.
  • 기본값은 REQUIRED이다.
  • 트랜잭션은 데이터베이스에서 제공하는 기술이므로 커넥션 객체를 통해 처리한다. 1개의 트랜잭션을 사용한다는 것은 하나의 커넥션 객체를 사용한다는 것이다.

→ 외부 트랜잭션내에 내부 트랜잭션이 있는 경우, 둘을 묶어 하나의 트랜잭션이 됩니다.

 

→ 스프링에서는 로직에 있는 트랜잭션을 논리 트랜잭션이라는 단위로 생각하고, 논리 트랜잭션들을 묶은 하나의 트랜잭션을 물리 트랜잭션이라고 한다.

  • 논리 트랜잭션 : 스프링이 트랜잭션 매니저를 통해 트랜잭션을 처리하는 단위
  • 물리 트랜잭션 : 실제 데이터베이스에 적용되는 트랜잭션으로, 커넥션을 통해 커밋/롤백하는 단위
  • 특징
    • 모든 논리 트랜잭션이 커밋 되어야 물리 트랜잭션이 커밋된다.
    • 하나라도 논리 트랜잭션이 롤백되면 물리 트랜잭션 내에 있는 모든 트랜잭션은 롤백된다.
    • 스프링에서는 트랜잭션이 여러 개인 경우, 첫 논리 트랜잭션이 물리 트랜잭션을 시작시키며 최종 커밋한다.
    • 외부 트랜잭션만이 커넥션 작업을 발생시킨다.
    • 내부 트랜잭션은 새로운 트랜잭션을 만들지 않는다.

트랜잭션 전파 동작 순서

  1. 외부 트랜잭션 시작
  2. 커넥션 생성
  3. setAutoCommit
    • true : 자동으로 프로그램이 정상으로 끝나면 commit, 에러가 발생하면 rollback
    • false : 사용자가 직접 commit/rollback
  4. 커넥션을 트랜잭션 동기화 매니저에 보관
  5. 트랜잭션 생성
  6. 로직에서 커넥션 사용
  7. 내부 트랜잭션 시작
  8. 트랜잭션 동기화 매니저에 기존 트랜잭션이 존재하는지 확인
    • 트랜잭션 동기화 매니저에 외부 트랜잭션 로직을 수행했던 커넥션이 보관되어 있다. 이 커넥션을 내부 트랜잭션에서 그대로 사용.
  9. 기존 트랜잭션에 참여, 새로운 트랜잭션을 생성하지 않는다.
  10. 로직에서 커넥션 사용
  11. 내부 트랜잭션(논리 트랜잭션) 커밋
  12. 외부 트랜잭션(논리 트랜잭션) 커밋
  13. DB 커넥션(물리 트랜잭션)에 커밋 호출.

→ 전파 속성은 REQUIRED를 전제로 한다.

  • 외부 롤백 트랜잭션 전파 순서

내부 트랜잭션 커밋 → 외부 트랜잭션 롤백 요청 → 트랜잭션 매니저에서 DB커넥션에 롤백 호출 → 데이터베이스에 롤백 적용 후 트랜잭션 종료

  • 내부 롤백 트랜잭션 전파 순서

내부 트랜잭션 롤백 → 트랜잭션 동기화 매니저 rollbackOnly = true로 표시 (DB 커넥션에 롤백을 호출X) → 외부 트랜잭션에서 커밋 요청 → rollbackOnly 설정 확인 → rollbackOnly = true 확인 후 롤백 및 예외(UnexpectedRollbackException)를 발생시킴

외부 트랜잭션의 경우 실제 커밋을 호출하기 위해 트랜잭션 동기화 매니저에서 커넥션을 흭득해야 하는데 그것을 rollbackOnly = true 막는다.

트랜잭션 전파 속성(Transaction Propagation)

1. 트랜잭션 전파 속성이란?

  • 이미 트랜잭션이 진행중일 때 추가 트랜잭션 진행을 어떻게 할 지 결정하는 것이다.

2. 다양한 스프링의 트랜잭션 전파 속성

  • REQUIRED
    • 스프링이 제공하는 기본적인(DEFAULT) 전파 속성이다.
    • 내부 트랜잭션이 기존에 존재하는 외부 트랜잭션에 참여한다.
    → 참여한다는 것은 외부 트랜잭션을 그대로 이어간다는 뜻이고, 외부 트랜잭션의 범위가 내부까지 확장되는 것을 의미한다.
  • REQUIRES_NEW
    • 외부 트랜잭션과 내부 트랜잭션을 완전히 분리하는 전파 속성
    • 2개의 물리 트랜잭션이 사용된다.
    • 2개의 물리 트랜잭션이 사용된다는 것은 각각의 DB 커넥션이 사용된다는 것이다.
    • 각각 트랜잭션 별로 커밋과 롤백이 수행된다.
    • 1개의 HTTP 요청에 대해 2개의 커넥션이 사용되는 것이다. 내부 트랜잭션이 처리 중일 때 외부 트랜잭션이 대기하는데, 이것은 데이터베이스 커넥션을 고갈시킬 수 있다. 그렇기에 REQUIRES_NEW 없이 해결가능한 문제는 최대한 대안책을 사용하는 것이 좋다.

  • SUPPORTS
    • 이미 시작된 트랜잭션이 있으면 참여, 그렇지 않으면 트랜잭션 없이 진행한다.
  • MANDATORY
    • 이미 시작된 트랜잭션이 있으면 참여하고, 없으면 새로 시작하는 대신 없으면 예외를 발생시킨다.
    • 혼자서 독립적으로 트랜잭션을 진행하면 안되는 경우에 사용
  • NOT_SUPPORTED
    • 이미 진행중인 트랜잭션이 있으면 이를 보류시키고, 트랜잭션을 사용하지 않도록 한다.
  • NEVER
    • 이미 진행중인 트랜잭션이 있으면 예외를 발생시키며, 트랜잭션을 사용하지 않도록 강제한다.
  • NESTED
    • 이미 진행중인 트랜잭션이 있으면 중첩(자식) 트랜잭션을 시작한다.
    • 트랜잭션 안에 다시 트랜잭션을 만드는 것으로, 독립적으로 트랜잭션을 만드는 REQUIRES_NEW와는 다르다.
    • 중첩(자식) 트랜잭션은 부모의 커밋, 롤백의 영향을 받지만 자신의 커밋, 롤백의 영향을 주지는 않는다.

[Reference]

'DB' 카테고리의 다른 글

JOIN으로 성능 개선하기  (0) 2025.02.16