반응형
반응형

1. 개요

 트랜잭션을 적용하기 위해 사용했던 @Transactional이 어떻게 트랜잭션이라는 부가기능을 제공하는지에 대한 매커니즘을 이해해보자.

 


2. AOP 기반의 트랜잭션 기능

 스프링 AOP를 활용하면 특정 패턴을 가진 클래스의 메서드에 부가 기능을 부여할 수 있고, 트랜잭션 기능도 어렵지 않게 부여할 수 있다.

 이는 PlatformTransactionManager와 같이 스프링에서 제공하는 트랜잭션 추상화 클래스를 사용하여 구현할수도 있다.

 

https://tlatmsrud.tistory.com/113

 

[Spring] 스프링 AOP / 용어 / 빈 후처리기

1. 개요 스프링 AOP를 이해하고, 빈 후처리기를 활용해 AOP를 구현해보자. 2. AOP 2.1. AOP가 뭔가요? AOP는 말 그대로 Aspect(관점) Oriented(지향) Programming(프로그래밍). 관점 지향적인 프로그래밍이다. 풀

tlatmsrud.tistory.com

 

 포스팅했던 트랜잭션 기능 구현 내용을 정리하면, 어드바이스에는 트랜잭션 기능을, 포인트컷에는 타겟 설정을 하고, 이 둘을 갖는 객체인 어드바이저어드바이저 빈을 스캔하는 자동 프록시 생성 객체를 빈으로 등록하여 구현한다.

 

 어찌됐던 아래와 같이 트랜잭션을 시작하고, 타겟 메서드를 실행하고, 트랜잭션을 Commit 또는 Rollback한 후 트랜잭션을 종료하게 된다.

 

스프링 AOP를 통한 트랜잭션 적용

 

 이와 같이 트랜잭션 기능을 부여하려면 AOP 기반의 여러 설정들이 필요한데, 이러한 설정들과 상호작용하여 트랜잭션 기능을 제공받게 하는 것이 바로 @Transactional 이다. 

 


2. @Transactional 선언만 해줬을 뿐인데??

 이 어노테이션을 메서드, 클래스, 인터페이스에 선언만 하면 타겟 메서드 호출 시 기본 속성을 갖는 트랜잭션이 시작된다. 4 가지 속성이 있으며 전파속성, 격리수준 속성, 제한시간 속성, 읽기전용 속성이다.

 

2.1. 전파 속성

 트랜잭션이 어떻게 전파되는지를 정의하는 속성이다. 예를들어 AClass, BClass에 @Transactional을 선언하고, AClass의 메서드 내부에서 BClass의 메서드가 실행된다고 가정해보자. 이때 트랜잭션은 어떻게 전파될까? AClass의 메서드 호출 시 트랜잭션이 시작되고, BClass의 메서드 호출 시 새로운 트랜잭션이 시작될까?

아니다. @Transactional 을 선언하게 되면 기본 전파 방식인 PROPAGATION_REQUIRED 방식을 사용하게 되어 BClass의 메서드는 자신에게 전파된 트랜잭션에 참여하게 된다.

 

 반대로 다른 전파 속성으로 설정한다면, 트랜잭션에 참여하지 않거나, 새로운 트랜잭션을 생성하도록 할 수 도있다. 

 

@Service
@Transactional
public class AClass {

    private final BClass bClass;
    
    public AClass(BClass bClass){
        this.bClass = bClass;
    }

    public void method(){
        // Data 처리 로직
        bClass.method();
        // Data 처리 로직
    }
}

..

@Service
@Transactional
public class BClass {

    public void method(){
        // Data 처리 로직
    }
}

 

 

2.2. 전파속성의 종류

 일반적으로 사용되는 3가지의 전파 속성이다.

 

1) PROPAGATION_REQUIRED

 가장 많이 사용되는 트랜잭션 전파 속성이다. 진행 중인 트랜잭션이 없으면 새로 시작하고, 있으면 이에 참여한다. 이 방식을 사용할 경우 AClass.method와 BClass.method는 하나의 작업 단위 즉, 하나의 트랜잭션으로 구성되게 되고, 두 메서드가 종료되기 전에 내부에서 예외 (정확히는 런타임 예외)가 발생한다면 둘다 롤백된다.

 

PROPAGATION_REQUIRED 전파 속성

 

2) PROPAGATION_REQUIRES_NEW

 NEW ! 항상 새로운 트랜잭션을 시작한다. 진행 중인 트랜잭션이 있건 없건 새로운 트랜잭션을 생성하고 시작한다. 이 방식을 사용할 경우 BClass의 method 실행 시 1번 트랜잭션과 독립되어 동작하는 2번 트랜잭션이 생성된다.

 BClass의 method가 정상적으로 호출 및 종료되면 2번 트랜잭션은 Commit 되므로, 이후 AClass의 method에서 예외가 발생한다 한들 BClass의 Commit된 내용은 Rollback되지 않는다.

 

PROPAGATION_REQUIRES_NEW 전파 속성

 

3) PROPAGATION_NOT_SUPPORTED

전파 지원 안해줘! 진행 중인 트랜잭션이 있건 없건 트랜잭션 없이 동작하도록 한다. 트랜잭션이 없으니 트랜잭션 전파 지원도 없다는 뜻으로 해석했다. 이 방식을 사용할 경우 DB Connection이 발생할 때마다 트랜잭션 없이 DB 연산이 수행되고 BClass 내부에서 Exception이 발생한다 하더라도, 그 전에 Commit 됐던 내용은 Rollback 되지 않는다.

이와 별개로  AClass는 호출했던 BClass 메서드에서 발생한 예외로 인해 Rollback 된다.

PROPAGATION_NOT_SUPPORTED 전파속성

 

 

 

2.3. 격리수준

 트랜잭션 격리 수준은 DB에서 동시에 여러 트랜잭션이 처리될 때, 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 어느정도까지 허용할거냐를 결정하는 것이다.

 격리 수준은 SERIALIZABLE, REPEATABLE READ, READ COMMITED, READ UNCOMMITED 가 있고, 기본적으로 DB 설정에 따르지만 트랜잭션 레벨에서도 설정이 가능하다. 이 내용은 매우 중요하기 때문에 따로 포스팅하도록 하겠다. 

 

2.4. 제한시간

 트랜잭션에 대한 제한시간을 설정할 수 있다. 기본 설정은 제한시간이 없는 것이다.

 

2.5. 읽기전용

 트랜잭션에서 읽기 작업만 수행할 수 있도록 제한하는 것이다. 만약 Update, Delete, Insert와 같이 데이터를 조작하는 행위를 할 경우 예외가 발생한다.

 


3. 어드바이스와 포인트컷

 @Transactional은 특정 메서드(포인트컷)에 특정 속성(어드바이스)을 갖는 트랜잭션을 생성하고 시작하도록 한다. 그럼 어디선가 @Transactional 을 포인트컷으로 지정하고, @Transactional에 속성 값에 설정한 트랜잭션 속성을 가져다가 어드바이스에서 트랜잭션 생성 시 사용해야 한다. 이 기능을 하는 클래스들이 뭔지 알아보자.

@Transactional을 통한 속성 설정

 

3.1. 포인트컷

 @Transactional이 선언된 타입 혹은 메서드에 대해서만 대상으로 선정하는 포인트컷이 필요한데, 이 기능을 하는 포인트컷이 바로 TransactionAttributeSourcePointcut 이다.

 이 클래스는 @Transactional 붙은 타입 혹은 메서드를 찾아 포인트 컷의 선정 결과로 돌려준다. @Transactional의 속성을 통해 트랜잭션의 속성도 정의하지만 포인트컷의 선정 대상으로도 사용된다.

 

3.2. 어드바이스

 @Transactional에 속성 값을 읽어 트랜잭션을 생성하는 어드바이스가 필요한데, 이 기능을 하는 어드바이스가 바로 TransactionInterceptor 이다. 정확히는 트랜잭션 매니저와 트랜잭션 속성 두가지를 설정하는데, 트랜잭션 속성은 AnnotationTransactionAttributeSource 라는 클래스에게 요청하면, 해당 클래스에서 @Transactional 에 입력된 속성을 읽어온다.

 

3.3. 어드바이저

 이 포인트컷과 어드바이스를 갖고 있는 어드바이저는 BeanFactoryTransactionAttributeSourceAdvisor 로 어플리케이션 실행 시 자동으로 빈으로 등록된다.


4. @Transactional 선언만 해줬을 뿐인데!!

정리하면, @Transactional 선언만 해주면 아래와 같은 매커니즘에 따라 동작하게 된다.

 

1) 어플리케이션 시작 시 TransactionAttributeSourcePointcut 포인트컷과 TransactionInterceptor 어드바이스를 갖는 BeanFactoryTransactionAttributeSourceAdvisor 어드바이저가 빈으로 등록된다. 

 

2) 빈 후처리기가 트랜잭션 기능을 부여하는 어드바이저 빈을 조회한다.

 

3) 어드바이저의 포인트 컷을 통해 @Transactional이 붙은 Bean 을 선정하고 프록시로 생성한다.

 

4. 생성한 프록시에 어드바이저를 연결한다. 

 

5. 완성된 프록시를 스프링 컨테이너에게 전달한다.

 

6. 스프링 컨테이너는 전달받은 프록시를 빈으로 등록하고 사용한다.

 

7. 추후 해당 프록시 빈이 호출될 경우 트랜잭션 속성에 따른 트랜잭션 부가기능이 수행된다.

 

반응형

+ Recent posts