본문 바로가기

Backend Development/Spring boot

[Spring boot] Exception에 따라 조건부로 Transaction Rollback 하기

아주 흔한 케이스는 아니지만 Rest Api호출 후 Exception으로 에러 코드를 전달할 시에 대부분은 Transaction rollback으로 DB에 저장된 내용은 다시 취소를 한다

 

그러나 특정 케이스에서는 DB 상태는 Rollback하지 않고  Front 단에는 에러코드를 전달하고 싶을때가 있다.

 

아래는 보통 사용하는 Transactional 처리이다.

    @Transactional
    public void executeService() {
        RestHistoryVO vo = new RestHistoryVO();
        vo.setCalldtlsId(Integer.parseInt(Instant.now()
            .atZone(ZoneId.of("Asia/Seoul"))
            .format(DateTimeFormatter.ofPattern("MMddHHmm").withLocale(Locale.ENGLISH))));
        vo.setRestId(Instant.now()
            .atZone(ZoneId.of("Asia/Seoul"))
            .format(DateTimeFormatter.ofPattern("yyyyMMddHHmm").withLocale(Locale.ENGLISH)));
        vo.setRestUrl("test");
        vo.setRestTy("test");
        vo.setRestParamtr("");

        batchMapper.addTestHistory(vo);
        
        // 강제로 Null Point Exception 발생
        vo = null;
        System.out.println(vo.getCalldt());

    }

 

예제 대로 Null Point 익셉션이 발생하게 되고

org.quartz.SchedulerException: Job threw an unhandled exception.
	at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
Caused by: java.lang.NullPointerException: null
	at com.sdp.service.job.sec.QuartzTestJobService.executeService(QuartzTestJobService.java:38)
	at com.sdp.service.job.sec.QuartzTestJobService$$FastClassBySpringCGLIB$$c8c54f48.invoke(<generated>)

 

 

롤백처리에 의해 레코드가 롤백된다. 저장이 안되어 있는것을 볼 수 있다.

noRollBackFor 옵션으로 특정 익셉션 발생시 롤백 안하기

 

 

Rollback을 회피할 Class를 지정하기 위해 RuntimeException을 상속해서 새 이름의 Exception을 만든다

public class BizException extends RuntimeException{

}

 

@Transactional어노테이션에 noRollbackFor옵션에 롤백을 적용하지 않을 익셉션 Class를 지정해 준다.

@Transactional(noRollbackFor = {BizException.class})
public void executeService() {
    RestHistoryVO vo = new RestHistoryVO();
    vo.setCalldtlsId(Integer.parseInt(Instant.now()
        .atZone(ZoneId.of("Asia/Seoul"))
        .format(DateTimeFormatter.ofPattern("MMddHHmm").withLocale(Locale.ENGLISH))));
    vo.setRestId(Instant.now()
        .atZone(ZoneId.of("Asia/Seoul"))
        .format(DateTimeFormatter.ofPattern("yyyyMMddHHmm").withLocale(Locale.ENGLISH)));
    vo.setRestUrl("test");
    vo.setRestTy("test");
    vo.setRestParamtr("");

    batchMapper.addTestHistory(vo);

    throw new BizException();
}

 

아래와 같이 새로만든 BizException이 발생한다.

org.quartz.SchedulerException: Job threw an unhandled exception.
	at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
Caused by: com.sdp.common.schedule.BizException: null
	at com.sdp.service.job.sec.QuartzTestJobService.executeService(QuartzTestJobService.java:36)
	at com.sdp.service.job.sec.QuartzTestJobService$$FastClassBySpringCGLIB$$c8c54f48.invoke(<generated>)

 

아래와 같이 롤백 처리가 되지 않고 레코드가 그대로 디비에 저장되어 있다.

 

-- The End --