스프링/6. 스프링 DB-2

50. 트랜잭션 전파 3

sdafdq 2023. 10. 16. 14:50

본격적으로 트랜잭션 전파에 대해 알아볼 것이다.

 

트랜잭션이 중첩적인,

 

그러니까 트랜잭션 도중 트랜잭션이 끝나지 않았는데(commit or rollback) 또 트랜잭션을 마주 한다면?

 

기존의 트랜잭션을 이어 받을 지, 새 트랜잭션을 만들어 진행 해야 할 지,

 

이런 것을 정하는 것이 트랜잭션 전파. propagation

 

 

 

우선, 트랜잭션 진행 중에 또 다른 트랜잭션을 시작하는 경우.

보통 트랜잭션을 이어 받는다..?

 

어.. 그렇기 보단 보통은 일단 스프링은

하나의 트랜잭션을 논리 트랜잭션이라고 정의한다. 그러니까, @Transactional 붙인거나 getTransaction 해서 시작하거나 해서 트랜잭션 도중의 범위들을 하나의 논리 트랜잭션 이라고 한다.

 

그리고, 이미 트랜잭션 진행 도중에 또 다른 트랜잭션이(또 다른 논리 트랜잭션) 시작되면, 이것들을 통으로 묶어 그걸 물리 트랜잭션 이라고 한다.

 

이렇게 개념을 만들어 두면, 단순한 원칙을 만들 수 있다.

모든 논리 트랜잭션이 커밋되어야 물리 트랜잭션이 커밋된다.

하나의 논리 트랜잭션 이라도 롤백되면 물리 트랜잭션은 롤백된다.

 

이것이 기본 옵션이다. REQUIRED 옵션인데, 바꿀 수 있다.

 

여튼 하나라도 롤백이면 다 롤백,

모두 커밋해야 제대로 커밋.

롤백은 or이고, 커밋은 AND

 

그리고 뭔가 코드 상 첫번째 트랜잭션 도중 두번째 트랜잭션이 안에 포함되는 거기 때문에,

첫번째 트랜잭션을 외부 트랜잭션 이라고도 함.

그래서 트랜잭션 닫는 순서도 내부부터.

 

두번째 트랜잭션은 저 첫번째 트랜잭션을 이어받음.

즉, 첫번째 트랜잭션의 범위가 넓어진다.

 

코드다.

@Test
void innerCommit(){
    log.info("외부 트랜잭션 시작");
    TransactionStatus status1 = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info("외부 트랜잭션 .isNewTransaction()={}", status1.isNewTransaction());

    log.info("내부 트랜잭션 시작");
    TransactionStatus status2 = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info("내부 트랜잭션 .isNewTransaction()={}", status2.isNewTransaction());

    log.info("내부 트랜잭션 commit");
    txManager.commit(status2);

    log.info("외부트랜잭션 commit");
    txManager.commit(status1);
}

첫번째 트랜잭션을 완료하기 전에 두번째 트랜잭션을 시작했다.

 

근데 좀 이상한 점이 있다.

두번째 트랜잭션은 첫번째 트랜잭션을 이어받는다고 했는데, 커밋을 두번 한다.

 

여기서 첫번째 트랜잭션의 isNewTransaction은 true이다. 저 메소드는 첫번째 새로운 트랜잭션인지 묻는 것이다. 당연 두번째 트랜잭션은 false

 

그리고 두번째 트랜잭션 시작할 때, 뭐 풀에서 커낵션을 가져온다던지 그런 게 로그로 나오지 않고,

Participating in existing transaction 기존 거래에 참여 라는 로그가 나온다.

즉, 같은 커넥션. 프록시도, 실제 커넥션도 같았다.

 

 

여기서 핵심은 저 첫번째 트랜잭션이 물리 트랜잭션을 관리한다.

즉, 첫번째 트랜잭션만 commit 하면 모두 commit 된다. 나머지는 commit해 봤자 커넥션으로 뭘 하지 않는다.

 

근데 진행 도중 하나라도 rollback이 나오면 거기서 그냥 다 rollback 시켜버리는 모양이다.

 

첫번째 트랜잭션에서는 새 트랜잭션을 생성하고, 그걸 트랜잭션 동기화 매니저(쓰레드로컬)에 보관.

두번째 트랜잭션은 먼저 기존에 트랜잭션이 있는지 확인하고, 있으면 참여.

 

트랜잭션 시작할 때, 우리가 status해서 받는 거 거기에 트랜잭션 생성한 결과들을(정보들을) 담아서 반환해 준다.

거기에 isNewTransaction() 신규인지 아닌 지(1빠인지 아닌 지) 묻는 것도 있다.

 

 

그래서 사실 첫번째 트랜잭션만 커밋하면 모두 커밋되긴 하는데,

일단 그래도 방문 -> 대문 닫듯이 트랜잭션을 시작의 역순으로 닫는 게 좋아 보인다.

'스프링 > 6. 스프링 DB-2' 카테고리의 다른 글

52. 트랜잭션 전파 5  (0) 2023.10.16
51. 트랜잭션 전파 4  (0) 2023.10.16
49. 스프링 트랜잭션 전파 2  (0) 2023.10.16
48. 스프링 트랜잭션 전파  (0) 2023.10.16
47. 트랜잭션과 예외 -활용  (0) 2023.10.16