트랜잭션을 시작하거나 기존 트랜잭션에 참여하는 방법을 결정하는 속성이다. 트랜잭션 경계의 시작 지점에서 트랜잭션 전파 속성을 참조해서 해당 범위의 트랜잭션을 어떤 식으로 진행시킬지 정할 수 있다.
이렇게 글로만 보면 트랜잭션 전파 속성은 왜 써야하는지 전혀 와닿지 않는다. 항상 필요에 의한 공부를 할 때 진정한 공부가 되는 것 같다.
e-커머스 회사를 다니고 있고, 고객 주문 + 주문 내역을 기록해주는 기능을 개발하라고 지시를 받았다! 어떻게 개발할 것인가?
트랜잭션을 어떻게 묶을까?
위의 상황을 분석해보면, 고객 주문은 성공을 했는데 주문 내역이 기록이 되지 않아 롤백된다면??? 이 얼마나 매출을 깍아먹는 개발자인가....
즉 지금 상황에서 트랜잭션을 어떻게 묶을지 결정할 수 있는 요인은
- 중요한 일(주문 내역), 중요하지 않은 일(로그) 묶음을 별개로 가져가자
이다. 즉, 주문이 실패하면 로그도 기록되지 않아야 하지만, 주문이 성공했는데 로그 실패 때문에 전체 롤백이 되면 안된다.
트랜잭션 전파 속성 1 - NESTED
이미 진행 중인 트랜잭션이 있으면 중첩 트랜잭션을 시작한다. 즉, 별개의 트랜잭션을 만드는 것이 아니라 트랜잭션 안에 다시 트랜잭션을 만든다. ( 이게 되는구나...? ) 즉, 독립적인 트랜잭션을 새로 만드는 REQUIRES_NEW와는 다르다.
- 부모 트랜잭션의 커밋,롤백 -> 중첩된 트랜잭션에 영향을 줌
- 중첩된 트랜잭션의 커밋,롤백 -> 부모 트랜잭션에 영향을 주지 않음!
즉, 위의 상황에 딱 맞는 구현이다. 주문은 부모 트랜잭션으로 설정하고, 로그는 중첩 트랜잭션으로 구현하면 된다.
트랜잭션 전파 속성 2 - REQUIRES_NEW
위에서 NESTED와 비교했던 속성이다. 이 전파 속성은 진행 중인 트랜잭션이 있으면 잠시 보류시키고 항상 새로운 트랜잭션을 시작한다.
class Service {
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void doSomething() {
// access a database using a DAO
}
}
- 서로 커밋, 롤백 영향이 없음. 왜냐하면 데이터베이스 관점에서 보면 서로 다른 별개의 트랜잭션이기 때문
트랜잭션 전파 속성 3 - REQUIRED
기본 속성이다. 미리 시작한 트랜잭션이 있으면 참여하고 아니면 시작한다. 매우 강력하고 유용하다고 하는데 어떠한 부분인지 와닿지는 않는다....
트랜잭션 롤백 예외 : rollbackFor
선언적 트랜잭션에서는 런타임 예외가 발생했을 때만 롤백한다.
왜 런타임 예외만 롤백해??
일반적으로 개발할 때, 체크 예외는 리턴 값대신 비즈니스적인 의미를 담아 던지는 예외이다. ( Effective Java 3/e 보면서 checked exception, unchecked exception을 언제써야 하는지 공부를 했다... ) 즉, 기본적으로 비즈니스 예외는 개발자에게 복구를 맡기고 프로그램적으로 문제가 있는 런타임시에만 롤백한다.
하지만, Checked Exception도 롤백하고 싶은 경우라면 아래와 같이 사용하면 된다.
@Transactional(rollbackFor = DataNotFoundException.class)
'Back-End > Spring' 카테고리의 다른 글
스프링 blocking vs non-blocking : R2DBC vs JDBC & WebFlux vs Web MVC (1) | 2020.07.01 |
---|---|
Spring DeleteAllBy...In 호출시 에러 ( TransactionRequiredException ) (1) | 2020.02.16 |
Spring Boot Test 및 심화 (0) | 2020.01.08 |
Spring을 이용하여 개발할 때 고민, 클린코드 짜기, 코드리뷰 항목 (0) | 2020.01.02 |
Spring @Order 어노테이션 (0) | 2019.11.28 |