[문제]
사용자가 발생한 경고 알람을 확인하면서 조치사항을 등록한다. 이때, Agent에 REST로 알람 해제 데이터를 보내줘야 하는데 Httpclienterrorexception이 발생하는 상황이다. Exception이 발생했을 경우 DB에 "알람 해제"를 commit이 되면 안 되고 rollback이 되어야 한다.
[문제 코드]
문제는 try-catch로 직접 예외처리를 할 경우 @Transactional(rollback=Httpclienterrorexception.class)가 작동되지 않는다.
@Transactional(rollbackFor="HttpClientErrorException.class")
public ResultBean alarmSolve(){
...
try{
...
RestTemplate rest = new RestTemplate();
String res = rest.postForObject(url, map, String.class);
if(res == null || !"success".equals(res)) {
resultBean.setResult(false);
return ajaxBean;
}
}catch(HttpClientErrorException e){
e.printStackTrace();
resultBean.setMsg(e.printStackTrace());
}catch(Exception e){
e.printStackTrace();
resultBean.setMsg(e.printStackTrace());
}
...
}
[해결]
catch에서 직접 예외처리를 하는 게 문제였으니, 예외처리를 하지 않고 throw를 해주면 rollbackFor이 작동된다.
@Transactional(rollbackFor="HttpClientErrorException.class")
public ResultBean alarmSolve(){
...
try{
...
RestTemplate rest = new RestTemplate();
String res = rest.postForObject(url, map, String.class);
if(res == null || !"success".equals(res)) {
resultBean.setResult(false);
return ajaxBean;
}
}catch(HttpClientErrorException e){
logger.warn("Httpclienterrorexception catch!!");
throw e;
}catch(Exception e){
e.printStackTrace();
resultBean.setMsg(e.printStackTrace());
}
...
}
[질문 및 답변]
Q1. @Transactional는 모든 예외에 대해서 rollback을 할까?
결론은 @Transcational의 rollbackFor 옵션은 기본적으로 RuntimeException과 Error에 대해서만 rollback 하고, Exception에 대해서는 rollback을 하지 않는다. 즉, unchecked exception이 발생하면 rollback 하고 checked exception이 발생하면 commit 한다. unchecked exception은 비즈니스상 예상하지 못한 예외여서 rollback 하고, checked exception은 의도했을 수 있어서 커밋을 한다는 전략을 가지고 있다.
[@Transactional rollbackFor 주석]
By default, a transaction will be rolling back on RuntimeException and Error but not on checked exceptions (business exceptions). See org.springframework.transaction.interceptor.DefaultTransactionAttribute.rollbackOn(Throwable) for a detailed explanation.
Q2. checked exception이 발생했을 때, rollback을 하고 싶으면 어떻게 해야 할까?
특정 예외에 대해 rollback을 하고 싶으면, @Transcational의 rollbackFor 옵션을 사용하면 된다.
rollbackFor = {Httpclienterrorexception.class}
만약 모든 예외에 대해서 전부 rollback을 하고 싶다면 Exception.class를 넣어주면 된다.
rollbackFor = {Exception.class}
[참고]
[Spring] @Transactional(rollbackFor={exceptionClass})
스프링에서 @Transactional을 사용하면 기본적으로 모든 예외에 대해 롤백하는 줄 알았다. 근데 아니었다.
da-nyee.github.io
'개발 > 1일1문제해결' 카테고리의 다른 글
[Java] Enum 클래스 실무 활용기 1 (with JavaScript) (1) | 2024.12.09 |
---|---|
[Network] 내부IP와 외부IP는 왜 따로 있을까? (0) | 2024.05.14 |
[REST API] POST 테스트 중 JSON 관련 double-quote 에러 (1) | 2024.03.25 |
[Tomcat] http로 redirect 되는 문제 (X-Forwarded 헤더) (0) | 2024.03.24 |
[Spring] @Autowired Nullpointexception 오류 해결 (+ Spring Security) (0) | 2024.03.21 |