[Spring] @Transactional 이 동작하지 않을 때
■ 개요
Spring 에선 @Transactional 이라는 아주 놀라운 어노테이션을 제공한다.
트랜잭션을 쉽고 간편하게 사용할 수 있도록 추상화해놓은 어노테이션이다.
함수 머리위에 붙이기만 하면 내부적으로 트랜잭션 처리를 해 준다!
--> 라고 생각했지만 @Transcational이 구현되고 동작하는 방식을 모른 채로
무작정 사용하면 원하는대로 동작하지 않는 경우가 많다.
이 글은 동작 방식을 설명하기 위한 것은 아니고,,
내가 원하는대로 트랜잭션이 걸리지 않을 경우 검토할만한 것들을 정리해 보았다.
Spring에서의 @Transactional의 동작 방식은 아래 글을 참고하면 자세히 알 수 있다.
(본문과도 연관됨)
Spring AOP에서 Proxy란 ? (velog.io)
■ 본문
1. @Transactional을 선언한 함수 내부에 try-catch구문
아래의 코드를 보자
public class FileService {
@Transactional
public FileBean selectFileInfo(String fileId) {
try {
//트랜잭션 처리할 함수
} catch(RuntimeException re) {
//에러처리
}
}
}
트랜잭션을 선언한 함수 내부에 롤백할 코드를 try-catch 구문이 감싸고 있다.
의식의 흐름으로 코딩을 하다 보면 놀랍게도 이렇게 작성할때가 있다.
에러를 밖으로 던져야 하는데 내부적으로 잡아버리니 함수는 성공 처리된다.
성공으로 처리되기 때문에 트랜잭션이 롤백되지 않는다.
2. @Transactional을 선언한 함수를 같은 클래스에서 호출할 경우
public class FileService {
public void copyFile(String fileId) {
FileBean file = this.selectFileInfo(fileId);
//....
}
@Transactional
public FileBean selectFileInfo(String fileId) {
//select File
}
}
@Transactional은 스프링 AOP기반으로 동작하기 때문에
같은 클래스 내부의 함수를 호출한 경우 동작하지 않는다.
자세한 내용은 위 개요의 velog 링크를 참고한다.
3. @Transactional이 걸린 함수가 private인 경우
public class FileService {
public void copyFile(String fileId) {
FileBean file = this.selectFileInfo(fileId);
//....
}
@Transactional
private FileBean selectFileInfo(String fileId) {
//select File
}
}
사실 private 로 선언되었다는 것은 같은 클래스 내부의 함수에서 호출된다는 말이므로 위의 2번과 같은 내용이다.
4. @Transactional이 걸린 함수 내부에서 CheckedException이 발생한 경우
public class FileService {
@Transactional
public FileBean selectFileInfo(String fileId) {
throw new IOException();
}
}
위의 코드처럼 트랜잭션 내부의 클래스에서 IOException(CheckedException) 이 발생하면 롤백이 될까?
따로 설정을 하지 않았다면 롤백되지 않고 커밋이 될 것이다.
자세한 내용은 아래의 링크를 참고한다.
Checked Exception을 대하는 자세 - Yun Blog | 기술 블로그 (cheese10yun.github.io)
■ 결론
@Transactional 어노테이션은 잘 사용한다면 매우 편하게 트랜잭션을 처리할 수 있다.
하지만 동작 방식이나 예외 사항이 있기 때문에 정확하게 알고 처리하는 것이 좋을 듯 하다.
복잡한 로직에 특정 부분만을 롤백처리 하고 싶다면
어노테이션이 아닌 선언적 트랜잭션으로 직접 처리하면 되겠다.
끝.