일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 유학
- 필라델피아
- 삼성 플렉스북
- kospi
- 펜실베이니아
- ue5
- spring
- mastering unreal engine
- flex하는게 아니었는데..
- rollbackOnly
- 증시
- AT&T
- HRD
- 학생비자
- java
- spring security
- @JsonView
- weblogic
- mysql
- jdk17
- 주식
- 인물
- 금융공학
- 최근증시
- JPA
- spring message converters
- 어학연수
- paper2d
- 월화수목금토익
- UE4
- Today
- Total
HeBhy, since 1983.
Spring @Transaction에서 Method별 선택적 전역 롤백 방지 (Prevent the JPA global transaction rollback on the specific method) 본문
Spring @Transaction에서 Method별 선택적 전역 롤백 방지 (Prevent the JPA global transaction rollback on the specific method)
HeBhy 2020. 7. 24. 23:08Spring에서 hibernate(Jpa)사용시, Spring transaction(@org.springframework.transaction.annotation.Transactional)을 사용하면 JpaTransactionManager.setGlobalRollbackOnParticipationFailure(true)가 기본값이라서.. method 단위 호출시 하위 어느곳에서라도 에러가 뜨면 전체가 롤백되어버리는데요,
대안으로 @Transactional(propagation = Propagation.NESTED)를 사용하려고 하면, 전역롤백 설정을 변경하지 않고는 해당 method에서만 롤백을 방지하는건 불가능하다는 에러가 뜹니다.
RollbackException: Transaction marked as rollbackOnly |
그럼 꼭 전역설정을 바꿔야 롤백을 막을수 있나? 그건 권장되지 않으니 그럴 필요는 없습니다.
예를 들어, 결제 처리를 하고 이메일을 보내야 하는데, 이메일 스케쥴에서 에러가 떴을 경우(이미 결제가 된 경우) 무시하고 정상 주문으로 처리하고 싶을 경우는 다음과 같이 하시면 됩니다.
즉, [2]에서 에러가떠도 [1]은 롤백하지 않습니다.
그러려면 아래 doTX() 에서 전역설정에 우선하기위해 noRollbackFor를 선언해줘야 합니다.
@Transactional(........)
public class OrderResetController ...... {
@Transactional(noRollbackFor = { Exception.class }) // class 전역 transactional보다 우선
@PostMapping("/order/doTx")
public Object doTx(HttpServletRequest request) {
HashMap<String, Object> entity = new HashMap<String, Object>();
Order order= this.orderyService.orderTx(request); // [1] 여기(결제)는 정상 수행되면
this.orderService.sendOrderMail(order, request); // [2] 여기(메일발송)은 실패해도 정상처리
entity.put("message", "결제가 완료되었습니다.");
return new JSONObject(entity);
}
}
그럼 이제 각각 orderTx()와 sendOrdermail()에서도(participated method) 새로운 트랜젝션을 잡도록 명시해줍니다.(둘 다 해주셔야 합니다. 트랜젝션 수가 늘어나는게 아니라, 이전 트랜젝션을 hold하고 진행하는 것입니다.)
(*주의: transaction이 분리되어 있으므로, 위 경우 order entity가 [2]에서는 detach되니 lazy child를 이용하기 위해선 다시 persist 해주셔야 합니다.)
public class OrderServiceImpl {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public orderTx(....) {
// .........
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public sendOrderMail(....) {
// .........
}
}
이상입니다.