서버개발을 하다보면 특히 DB와 연동되는 부분에서 @Transactional 어노테이션이 자주 쓰입니다.
어노테이션을 붙여주는 것만으로도 DB에 수행되는 쿼리들을 하나의 transaction으로 묶어줄 수 있으며, 속성에 따라서는 exception 종류에 따라 rollback 도 가능합니다.
어떻게 어노테이션을 붙여주는 것만으로도 이것이 가능할까요? 지금부터 알아봅시다.
@Transactional 어노테이션은 Proxy 방식으로 동작한다
"어노테이션을 붙여서 Proxy 방식으로 동작한다" 어디서 많이 보시지 않았나요? 네 맞습니다. @Transactional 어노테이션은 Spring AOP의 대표적인 예입니다. 혹시 AOP에 대해 아직 모르신다면 아래 글을 먼저 읽고 와주세요!
[Spring] AOP - 관점 지향 프로그래밍 이란?
[Spring] Spring AOP 프록시 - JDK Proxy(JDK Dynamic Proxy), CGLib
따라서 기존 코드를 바꾸지 않고도, AOP proxy가 기존 코드를 가로채서 앞 뒤로 transaction 처리를 할 수 있는 코드를 배치해서 하나의 transaction 으로 처리될 수 있는 것이죠.
@Service
@RequiredArgsConstructor
public class SampleService {
public void insertData(){
// do something
}
}
예를 들어 위와같은 서비스 로직이 하나 있다고 가정해봅시다. 만약 insertData 메소드에 @Transactional 어노테이션을 붙이게 되면
public class TransactionProxy{
private final TransactonManager manager = TransactionManager.getInstance();
public void transactionLogic() {
try {
manager.begin(); // 트랜잭션 전처리(트랜잭션 시작, autoCommit(false) 등)
insertData(); // 기존 로직
manager.commit(); // 트랜잭션 후처리(트랜잭션 커밋 등)
} catch ( Exception e ) {
manager.rollback(); // 트랜잭션 오류 발생 시 롤백
}
}
위 메소드에 대한 호출이 들어왔을 때 AOP proxy가 이를 가로채서 위와 같은 형태로 실행을 시키도록 해줍니다.
주의할 점
1. 메소드가 private 으로 돼있으면 @Transactional 어노테이션을 사용할 수 없습니다.
프록시 객체는 타겟 객체/인터페이스를 상속 받아서 구현하는데, private으로 되어 있으면 자식인 프록시 객체에서 호출할 수 없습니다. 따라서 @Transactional 이 붙는 메소드, 클래스는 프록시 객체에서 접근 가능한 레벨로 지정해야 합니다.
2. 트랜잭션은 객체 외부에서 처음 진입하는 메소드를 기준으로 동작합니다.
@transactional 어노테이션이 붙은 메소드 안에 어떤 메소드를 호출하는데 그 메소드에도 @Transactional 어노테이션이 붙어있을 수 있습니다. 하지만 AOP proxy는 호출시점에 target을 가로채기때문에 처음 진입하는 메소드를 기준으로만 동작합니다.
출처:
- AOP와 @Transactional의 동작 원리
- [Spring] @Transactional의 이해
'Spring' 카테고리의 다른 글
[Maven] Maven dependency의 Scope 옵션 (0) | 2023.04.09 |
---|---|
[Maven] Maven이란? (feat. Maven lifecycle) (1) | 2023.04.09 |
[JPA] 비관적 락(Pessimistic Lock)과 낙관적 락(Optimistic Lock) (0) | 2022.11.01 |
[Spring] Spring AOP 프록시 - JDK Proxy(JDK Dynamic Proxy), CGLib (0) | 2022.10.30 |
[JPA] @OneToMany 단방향을 사용하면 안되는 이유 (0) | 2022.10.27 |