Transaction Propagation 종류
- REQUIRED (default)
- 기존에 시작된 트랜잭션이 있으면 유효성을 검사해서 문제가 있다면 Exception 을 던지고 문제가 없으면 기존의 시작된 트랜잭션을 사용한다.
- 만약 기존에 시작된 트랜잭션이 없다면? -> 새로운 트랜잭션을 생성한다.
- 실무에서는 거의 이 옵션을 주로 사용한다.
- REQUIRES_NEW
- 부모 트랜잭션이 있더라도 항상 새로운 트랜잭션을 시작한다.
- 이미 진행중인 트랜잭션이 있으면 트랜잭션을 잠시 보류시킨다.
- 그리고 자식 트랜잭션이 완료(커밋 혹은 롤백)되면 보류되었던 트랜잭션이 다시 활성화된다.
- SUPPORTS
- 기존에 시작된 트랜잭션이 있으면 유효성을 검사해서 문제가 있다면 Exception 을 던지고 문제가 없으면 기존의 시작된 트랜잭션을 사용한다.
- 만약 기존에 시작된 트랜잭션이 없다면? -> 새로운 트랜잭션을 생성하지 않는다.
- 기존의 트랜잭션이 있다면? -> 기존 트랜잭션에 참여한다.
- NESTED
- 중첩된 트랜잭션은 먼저 시작된 부모 트랜잭션의 커밋과 롤백에 결과에 따라 자식 트랜잭션이 영향을 받는다.
- 하지만 자식의 커밋과 롤백은 부모 트랜잭션에게 영향을 주지 못한다.
- 예를들어 부모의 로그 트랜잭션이 롤백되면 자식의 로그 트랜잭션도 같이 롤백되지만, 반대로 자식의 로그 트랜잭션이 롤백돼도 부모의 로그 작업에 이상이 없다면 부모 트랜잭션은 정상적으로 커밋된다.
- MANDATORY
- 기존에 시작된 트랜잭션이 있으면 유효성을 검사해서 문제가 있다면 Exception 을 던지고 문제가 없으면 기존의 시작된 트랜잭션을 사용한다.
- 만약 기존에 시작된 트랜잭션이 없다면? -> Exception 을 던진다.
- 혼자서는 독립적으로 트랜잭션을 진행하면 안되는 경우에 사용한다.
- NOT_SUPPORTED
- 기존에 트랜잭션이 있으면 중단하고, 트랜잭션을 생성하지 않은 상태에서 비즈니스 로직을 수행합니다.
- NEVER
- 기존에 트랜잭션이 있으면 Exception을 던집니다.
- 트랜잭션을 사용하지 않도록 강제합니다.
코드 예시
REQUIRED (default)
// 부모 트랜잭션
@Transactional(rollbackFor=Exception.class)
public void parentLogic() {
parent.create(new Parent("엄마"));
childLogic(new Child("자식")); // 자식 트랜잭션 요청
parent.create(new Parent("엄마"));
}
// 자식 트랜잭션
@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
public void childLogic(String name) {
try {
child.create(name);
throw new RuntimeException("자식이 문제");
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
- 부모는 멀쩡한데 자식이 문제가 생겼을 경우다.
- REQUIRED 의 핵심은
의리
이다.
- 자식이 문제가 생기는 경우 부모가 다 정상수행을 했다 하더라도 모두 롤백이 된다.
// 부모 트랜잭션
@Transactional(rollbackFor=Exception.class)
public void parentLogic() {
parent.create(new Parent("엄마"));
childLogic(new Child("자식")); // 자식 트랜잭션 요청
parent.create(new Parent("엄마"));
throw new RuntimeException("부모가 문제");
}
// 자식 트랜잭션
@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
public void childLogic(String name) {
try {
child.create(name);
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
- REQUIRED 의 핵심은
의리
이다.
- 부모가 문제가 생겼을 때에도 모두 롤백된다.
REQUIRES_NEW
// 부모 트랜잭션
@Transactional(rollbackFor=Exception.class)
public void parentLogic() {
parent.create(new Parent("엄마"));
childLogic(new Child("자식")); // 자식 트랜잭션 요청
parent.create(new Parent("엄마"));
}
// 자식 트랜잭션
@Transactional(propagation=Propagation.REQUIRED_NEW, rollbackFor=Exception.class)
public void childLogic(String name) {
try {
child.create(name);
throw new RuntimeException("자식이 문제");
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
- REQUIRES_NEW 의 핵심은 각개전투이다.
- 부모와 자식간의 영향은 없다.
- 위의 경우 처럼 자식에게만 문제가 있는 경우는 부모는 정상적으로 커밋되고 자식은 로백된다.
// 부모 트랜잭션
@Transactional(rollbackFor=Exception.class)
public void parentLogic() {
parent.create(new Parent("엄마"));
childLogic(new Child("자식")); // 자식 트랜잭션 요청
parent.create(new Parent("엄마"));
throw new RuntimeException("부모가 문제");
}
// 자식 트랜잭션
@Transactional(propagation=Propagation.REQUIRED_NEW, rollbackFor=Exception.class)
public void childLogic(String name) {
try {
child.create(name);
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
- 위의 경우처럼 부모에서만 문제가 있는 경우 부모는 롤백, 자식은 커밋된다.
NESTED
// 부모 트랜잭션
@Transactional(rollbackFor=Exception.class)
public void parentLogic() {
parent.create(new Parent("엄마"));
childLogic(new Child("자식")); // 자식 트랜잭션 요청
parent.create(new Parent("엄마"));
}
// 자식 트랜잭션
@Transactional(propagation=Propagation.NESTED, rollbackFor=Exception.class)
public void childLogic(String name) {
try {
child.create(name);
throw new RuntimeException("자식이 문제");
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
- NESTED 의 핵심은 체크포인트이다.
- NESTED 호출 직전까지 일단 저장을 해놓는다.
- 위의 경우처럼 자식 트랜잭션에서 문제가 발생하면 체크 포인트 까지만 롤백된다.
- 그렇기 때문에 부모 트랜잭션은 커밋, 자식 트랜잭션은 롤백된다.
// 부모 트랜잭션
@Transactional(rollbackFor=Exception.class)
public void parentLogic() {
parent.create(new Parent("엄마"));
childLogic(new Child("자식")); // 자식 트랜잭션 요청
parent.create(new Parent("엄마"));
throw new RuntimeException("부모가 문제");
}
// 자식 트랜잭션
@Transactional(propagation=Propagation.NESTED, rollbackFor=Exception.class)
public void childLogic(String name) {
try {
child.create(name);
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
- NESTED 의 핵심은 체크포인트이다.
- 자식 트랜잭션에서 문제가 없으면 그 내용은 부모 트랜잭션의 일부가 된다.
- 하지만 여기서 부모 트랜잭션에서 문제가 발생한다면? -> 이미 부모 트랜잭션에 일부가 되었으므로 같이 롤백된다.
REFERENCES