상세 컨텐츠

본문 제목

@Transactional 기초 및 주의사항

Spring/개념

by Chan.94 2023. 5. 6. 20:45

본문

반응형

@Transactional

@Transactional은 클래스 또는 메소드에 사용할 수 있으며 @Transactional이 포함된 메소드가 호출될 경우, 프록시 객체가 생성된다. 이 방식을 선언적 트랜잭션이라고 부른다.
프록시 객체는 해당 메소드 실행 이전에 PlatformTransactionManager를 사용하여 트랜잭션을 시작하고 결과에 따라 Commit 또는 Rollback 한다.

 

@Transactional 어노테이션은 프록시 방식으로 동작한다. 프록시 방식이 무엇인지 간단하게 설명하고 넘어가겠다.

@Service
@RequiredArgsConstructor
public class SampleService {

    @Transactional
    public void study(){
        // do something
    }
}

study 메소드가 실행되게 되면 실제로는 아래와 같이 동작하게 된다.

public class TransactionProxy{
    private final TransactonManager manager = TransactionManager.getInstance();

    public void transactionLogic() {
        try {
           manager.begin(); // 트랜잭션 전처리(트랜잭션 시작, autoCommit(false) 등)
           study(); // 기존 로직
           manager.commit(); // 트랜잭션 후처리(트랜잭션 커밋 등)
        } catch ( Exception e ) {
            manager.rollback(); // 트랜잭션 오류 발생 시 롤백
        }
    }
}

두 포스팅의 내용을 참고하면 이해가 좀 더 쉬울 것이다.

[Spring/디자인패턴] - 프록시 패턴(Proxy Pattern)

[Spring/개념] - Spring AOP (Proxy)

 

Commit / Rollback

트랜잭션의 가장 중요한 부분 중 하나는 Commit과 Rollback일 것이다. 기본적인 Commit Rollback Rule은 다음과 같다.

Commit - CheckedException or 예외가 없을 때
Rollback - UncheckedException

 

CheckedException(SOLException 등) 같은 경우는 Commit이 진행된다. 보통 SQL에서 에러가 발생하게 되면 Rollback이 진행되어야 할 것이다. 그렇기 때문에 Rollback Rule을 설정할 수 있게 옵션으로서 제공한다.

 

해당 내용은 checked / UnChecked Exception / @Transactional rollback 포스팅을 확인하기 바란다.

 

propagation (전파속성)

REQUIRED (Defualt): 이미 진행 중인 트랜잭션이 있다면 해당 트랜잭션 속성을 따르고, 진행 중이 아니라면 새로운 트랜잭션을 생성한다.
REQUIRES_NEW: 항상 새로운 트랜잭션을 생성한다. 이미 실행 중인 트랜잭션이 있다면 잠깐 보류하고 해당 트랜잭션 작업을 먼저 실행한다.
SUPPORT: 이미 실행 중인 트랜잭션이 있다면 해당 트랜잭션의 속성을 따르고, 없다면 트랜잭션을 설정하지 않는다.
NOT_SUPPORT: 이미 실행 중인 트랜잭션이 있다면 보류하고, 트랜잭션 없이 작업을 수행한다.
MANDATORY: 이미 실행 중인 트랜잭션이 있어야만 작업을 수행한다. 없다면 Exception을 발생시킨다.
NEVER: 트랜잭션이 실행 중이지 않을 때 작업을 수행한다. 트랜잭션이 있다면 Exception을 발생시킨다.
NESTED: 실행 중인 트랜잭션이 있다면 중첩된 트랜잭션이 실행되며, 존재하지 않으면 REQUIRED와 동일하게 실행된다.

 

REQUIRED와 REQUIRES_NEW 두 가지 옵션을 자주 사용할 것이다. 두 옵션은 꼭 기억하고 넘어가자.

 

주의사항

1. 트랜잭션은 객체 외부에서 처음 진입하는 메소드를 기준으로 동작한다.

@Transactional 어노테이션이 붙은 메소드 안에 어떤 메소드를 호출하는데 그 메소드에도 @Transactional 어노테이션이 붙어있을 수 있습니다. 하지만 AOP proxy는 호출시점에 target을 가로채기때문에 처음 진입하는 메소드를 기준으로만 동작한다. 

 

2. 접근제한자가 private이라면 사용할 수 없다.

프록시 객체는 타겟 객체/인터페이스를 상속 받아서 구현하는데, private으로 되어 있으면 자식인 프록시 객체에서 호출할 수 없습니다. 따라서 @Transactional 이 붙는 메소드, 클래스는 프록시 객체에서 접근 가능한 레벨로 지정해야 한다.

private 에 @Transactional을 적용한다고 하면 IDE에서 컴파일 오류를 확인할 수 있다.

반응형

관련글 더보기

댓글 영역

>