REQUIRED
기본 속성, 부모 트랜잭션 내에서 실행(부모 트랜잭션 전파)하며 부모 트랜잭션이 없는 경우 새로운 트랜잭션을 생성한다.
한개의 트랜잭션으로 묶이기 때문에 부모나 자식 어디에서든 예외가 발생할 경우 둘 다 롤백 된다.
부모가 문제인 경우
@Transactional
public void saveWithRequiredAndParentFailed(Parent parent, Child child) {
parentRepository.save(parent);
childService.saveWithRequired(child, false);
throw new RuntimeException();
}
@Transactional(propagation = Propagation.REQUIRED)
public void saveWithRequired(Child child, boolean exception) {
childRepository.save(child);
if (exception) {
throw new RuntimeException();
}
}
@Test
@DisplayName("propagation이 REQUIRED, 부모가 문제인 경우 둘 다 Rollback 된다.")
void saveWithRequiredAndParentFailed() {
// when
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> parentService.saveWithRequiredAndParentFailed(parent, child));
// then
assertThat(parentRepository.count()).isZero();
assertThat(childRepository.count()).isZero();
}
자식이 문제인 경우
@Transactional
public void saveWithRequiredAndChildFailed(Parent parent, Child child) {
parentRepository.save(parent);
childService.saveWithRequired(child, true);
}
@Transactional(propagation = Propagation.REQUIRED)
public void saveWithRequired(Child child, boolean exception) {
childRepository.save(child);
if (exception) {
throw new RuntimeException();
}
}
@Test
@DisplayName("propagation이 REQUIRED, 자식이 문제인 경우 둘 다 Rollback 된다.")
void saveWithRequiredAndChildFailed() {
// when
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> parentService.saveWithRequiredAndChildFailed(parent, child));
// then
assertThat(parentRepository.count()).isZero();
assertThat(childRepository.count()).isZero();
}
SUPPORTS
이미 시작된 트랜잭션이 있으면 참여하고, 그렇지 않으면 트랜잭션 없이 진행한다.
REQUIRES_NEW
부모 트랜잭션을 무시하고 새로운 트랜잭션을 생성한다.
부모가 문제인 경우는 자식 트랜잭션이 새로 생성되었기 때문에 부모만 롤백된다.
하지만 자식이 문제인 경우는 둘 다 롤백된다. (호출 받는 자식 입장에서 REQUIRES_NEW가 적용되기 때문에 부모 입장에서는 1개의 트랜잭션이다.)
아예 새로운 트랜잭션이 되려면 다른 쓰레드로 호출해야 한다.
부모가 문제인 경우
@Transactional
public void saveWithRequiresNewAndParentFailed(Parent parent, Child child) {
parentRepository.save(parent);
childService.saveWithRequiresNew(child, false);
throw new RuntimeException();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveWithRequiresNew(Child child, boolean exception) {
childRepository.save(child);
if (exception) {
throw new RuntimeException();
}
}
@Test
@DisplayName("propagation이 REQUIRES_NEW, 부모가 문제인 경우 부모만 Rollback 된다.")
void saveWithRequiresNewAndParentFailed() {
// when
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> parentService.saveWithRequiresNewAndParentFailed(parent, child));
// then
assertThat(parentRepository.count()).isZero();
assertThat(childRepository.count()).isOne();
}
자식이 문제인 경우
@Transactional
public void saveWithRequiresNewAndChildFailed(Parent parent, Child child) {
parentRepository.save(parent);
childService.saveWithRequiresNew(child, true);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveWithRequiresNew(Child child, boolean exception) {
childRepository.save(child);
if (exception) {
throw new RuntimeException();
}
}
@Test
@DisplayName("propagation이 REQUIRES_NEW, 자식이 문제인 경우 둘 다 Rollback 된다.")
void saveWithRequiresNewAndChildFailed() {
// when
try {
parentService.saveWithRequiresNewAndChildFailed(parent, child);
} catch (Exception e) {
}
// then
assertThat(parentRepository.count()).isZero();
assertThat(childRepository.count()).isZero();
}
MANDATORY
SUPPORTS와 비슷하게 이미 시작된 트랜잭션이 있으면 참여한다.
하지만, 트랜잭션이 시작된 것이 없으면 새로 시작하지 않고 예외를 발생시킨다.
독립적으로 트랜잭션을 진행하면 안 되는 경우에 사용한다.
NOT_SUPPORTED
트랜잭션을 사용하지 않게 한다. 이미 진행 중인 트랜잭션이 있으면 보류시킨다.
NEVER
트랜잭션을 사용하지 않도록 강제한다.
트랜잭션이 진행중이면 예외를 발생시킨다.
NESTED
이미 진행중인 트랜잭션이 있으면 중첩 트랜잭션을 시작한다.
중첩된 트랜잭션은 먼저 시작된 부모 트랜잭션의 커밋과 롤백에는 영향을 받지만 자신의 커밋과 롤백은 부모 트랜잭션에게 영향을 주지 않는다.
'Spring' 카테고리의 다른 글
OSIV와 성능 최적화 (0) | 2022.03.25 |
---|---|
JPA 지연 로딩과 조회 성능 최적화 (2) (0) | 2022.03.07 |
JPA 지연 로딩과 조회 성능 최적화 (1) (0) | 2022.03.06 |
Log4j에서 SLF4J + Logback 으로 전환하기 (0) | 2022.02.03 |
댓글