본문 바로가기

Spring

@Transactional 동작 방식

이번 포스트를 보기 앞서 이전 포스트를 보고 오시기 바랍니다.

https://jaystorage.tistory.com/25

 

AOP와 Spring AOP

AOP (Aspect Oriented Programming)란 AOP는 관점 지향 프로그래밍을 의미한다. 처음 이 단어를 접하면 객체지향(OOP), 절차지향(PP)과 완전히 다른 새로운 개념인지 의문이 들 수 있으나 AOP는 기본적으로 OOP

jaystorage.tistory.com

 


 

@Transactional 이란?

 

@Transactional 어노테이션은 Spring에서 제공하는 어노테이션으로 메소드나 클래스에 적용하여 트랜잭션 경계를 지정할 수 있게 만든다. @Transactional 어노테이션을 사용하면 해당 메소드나 클래스의 메소드 실행이 트랜잭션 경계 내에서 이루어진다.

 

Transaction : 데이터베이스의 상태를 변화시키기 위해 수행하는 작업의 논리적 단위

 


 

@Transactional 은 Proxy 방식으로 동작한다

 

@Transactional 어노테이션은 Spring AOP의 대표적인 예시이다. 따라서 기존 코드를 바꾸지 않고도 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(); // 트랜잭션 오류 발생 시 롤백
        }
    }
}

 


 

@Transactional은 어떤 상황에서 rollback을 진행하는가

 

@Transactional 어노테이션은 여러 옵션을 가지고 있다. 하지만 @Transactional에 아무 옵션을 적용하지 않으면 @Transactional은 기본적으로 RuntimeException과 Error가 발생했을 때 rollback을 진행한다.

즉 @Transactional은 아무 옵션을 적용하지 않으면 아래와 같다고 볼 수 있다.

@Transactional(rollbackFor = {RuntimeException.class, Error.class})
public void myMethod(){
    …
}

 

@Transactional 옵션

 

@Transactional 은 트랜잭션의 경계를 설정할 때 아래와 같이 다양한 옵션을 설정할 수 있다.  

참고로 옵션 사용 방법은 다음과 같다.

 

@Transactional(propagation = Propagation.REQUIRED)
public void requiredMethod() {
    // 로직
}

 

 

1. 트랜잭션 전파(Propagation)

Propagation 옵션은 트랜잭션 전파 동작 방식을 정의하는데 사용된다. 전파 옵션은 메서드가 호출될 때 이미 진행 중인 트랜잭션이 있는 경우 새로운 트랜잭션을 시작할지, 기존 트랜잭션에 참여할지 등을 결정한다. 즉 Propagation은 트랜잭션을 수행하다가 다른 트랜잭션을 마주했을 때 처리 방식에 대한 옵션이다.

  • REQUIRED
    Default 설정. 이미 시작된 트랜잭션이 있으면 참여하고 없으면 새로 트랜잭션을 생성해 시작한다. 하나의 트랜잭션이 시작된 후 다른 트랜잭션 경계가 설정된 메소드를 호출하면 자연스럽게 같은 트랜잭션으로 묶임

  • SUPPORTS
    이미 시작된 트랜잭션이 있으면 참여하고, 없으면 트랜잭션 없이 진행

  • MANDATORY
    이미 시작된 트랜잭션이 있으면 참여하고, 없으면 예외 발생
    즉 현재 트랜잭션이 반드시 존재해야 함

  • REQUIRES_NEW
    항상 새로운 트랜잭션을 시작하고, 이미 진행 중인 트랜잭션이 있으면 이를 일시 중지

  • NOT_SUPPORTED
    트랜잭션을 전혀 사용하지 않고, 이미 진행 중인 트랜잭션이 있으면 일시 중지

  • NEVER
    트랜잭션을 강제로 사용하지 않고, 이미 진행 중인 트랜잭션이 있으면 예외를 발생
    즉 트랜잭션을 지원하지 않는 설정

  • NESTED
    이미 진행 중인 트랜잭션이 있으면 중첩 트랜잭션을 시작, 단 중첩 트랜잭션은 부모 트랜잭션에 영향을 주지 않음

 

2. 트랜잭션 격리 수준(Isolation)

Isolation 옵션은 트랜잭션 격리 수준을 설정하는 데 사용된다. 트랜잭션 격리 수준은 동시에 실행되는 여러 트랜잭션 간의 상호 작용 방식을 정의하여 데이터의 일관성과 무결성을 보장한다. 다시 말해 Isolation 옵션은 트랜잭션의 작업 결과를 다른 트랜잭션에게 어떻게 노출할 것인지를 결정하는 기준이라고 할 수 있다.

 

  • DEFAULT
    데이터 액세스 기술 또는 DB의 디폴트 설정을 따른다. 참고로 대부분의 DB는 READ_COMMITTED를 기본 격리 수준으로 갖는다.

  • READ_UNCOMMITTED
    커밋되지 않는 데이터에 대한 읽기 허용.

  • READ_COMMITTED
    커밋된 데이터에 대한 읽기 허용

  • REPEATABLE_READ
    동일 필드에 대해 다중 접근 시 모두 동일한 결과를 보장

  • SERIALIZABLE
    읽기 작업에도 공유 잠금을 설정하게 되고, 다른 트랜잭션에서 변경하지 못함

 

3. Timeout : 트랜잭션의 타임아웃 시간을 설정

4. ReadOnly : 트랜잭션을 읽기 전용으로 설정

5. rollbackFor : 롤백할 예외 유형을 지정

6. noRollbackFor: 롤백하지 않을 예외 유형을 지정

 


 

@Transactional 사용 시 주의할 점

 

1. 메소드가 private 으로 되어있으면 @Transactional 어노테이션을 사용할 수 없다.

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

 

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

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

 


출처 : 
https://www.youtube.com/watch?v=taAp_u83MwA
https://www.youtube.com/watch?v=cc4M-GS9DoY
https://www.youtube.com/watch?v=aX9c7z9l_u8
https://jhyonhyon.tistory.com/67
https://gngsn.tistory.com/152

 

'Spring' 카테고리의 다른 글

Bean 스코프  (0) 2024.07.16
Spring, Spring Boot 차이  (0) 2024.07.14
JDK Dynamic Proxy vs CGLIB Proxy  (0) 2024.07.02
AOP와 Spring AOP  (0) 2024.06.26
SL4J와 Logback을 이용한 Logging  (0) 2024.03.03