백엔드/Spring

@Transactional : 해줘야 할 상황. rollback 되지 않을 때.

wintertreey 2025. 6. 25. 16:09

Service에서 로직을 수행할때 묶어서 처리해야할 다수의 메소드가 있을 경우, 묶어서 처리해줘야한다. 

 

 

꼭 여러개의 메소드가 있다고 해서 Transactional을 걸어줘야하는건 아니다.

만약 다수의 메소드라 해도 SELECT .. 만 해주는 등 R 작업만 해준다면 꼭 묶음 처리해줘야할 필요가 없기 때문.

 

읽어오기만 하는 작업만 이어도 Pager일 경우엔 해줘야한다. 

 

 


@Transactional
public void insertInfo(Map<String, Object> paramMap) throws Exception {

	getInfo();
	insertUser();
	updateInfo(); //에러발생

}



 

이렇게 여러개의 메소드를 수행한다고 가정해보자.

 

여러 메소드를 수행하다가 한 메소드에서 에러가 발생한다면, 전체insertInfo()는 rollback되어야 의도한대로 db가 관리된다. 

그러나 updateInfo()에서 에러가 발생했는데, getInfo(), insertUser()의 메소드는 실행되고 commit된것을 확인.

상단에 트랜잭션 어노테이션을 붙여줬는데도 묶어서 처리가 되지 않은 것을 발견. 

 

 

처음엔 무대뽀로 SqlSession 불러서 commit(), rollback()해서 처리했다가 지움... ㅋㅋ.....

그렇게해도 결과가 나오지만 안 예쁘니까...ㅠ

 

 

이유 및 해결방안

 

 

스프링은 기본적으로 RuntimeException, Error 언체크드 예외에 대해서만 롤백을 수행한다. 만약 BizException이 Exception을 직접 상속한 체크드 예외라면, 기본 설정으로는 롤백 대상이 아니어서 커밋이 일어난다.

 

 

 

 

Transaction이 rollback 해주는 예외처리들의 종류에는 두 가지가 있다.

 

기본적으로 롤백되는 예외처리들 : 언체크드 error

  1. {@link java.lang.RuntimeException} 및 그 하위 클래스
    예시:
    • NullPointerException
    • IllegalArgumentException
    • IndexOutOfBoundsException
    • IllegalStateException
    • CustomException extends RuntimeException
  2. {@link java.lang.Error} 및 그 하위 클래스
    예시:
    • OutOfMemoryError
    • StackOverflowError

 

에러가 발생했던 updateInfo()의 경우 Bizexcetpion 으로 예외처리를 하고 있었고, Bizexception은 Exception을 상속받는 하위클래스였다. 즉 Transaction에서 자동으로 처리해주는 예외처리 중 하나가 아니였기에 발생한 문제였던 것.

 

해결방법 1.

public class BizException extends RuntimeException {

}

메소드내에서 BizException으로 예외처리를하고, Exception으로 상속받고 있던 BizException을 수정하여 RuntimeException을 상속받는걸로 해준다. 

 

 

해결방법 2.

@Transactional(rollbackFor = BizException.class)
public void insertInfo(Map<String, Object> paramMap) throws Exception {

	getInfo();
	insertUser();
	updateInfo(); //에러발생

}

 

해당 메소드만 트랜잭션을 걸어주고 BizException으로 예외처리하는 다른 메소드들에는 영향을 받게 하지 않고자 한다면, 해당 메소드의 트랜잭션 어노테이션에 롤백처리를 해줄 수도 있다. 나는 그냥 1번 방법을 선택하였다.