본문 바로가기
Spring&Spring Boot

(Spring/Spring Boot) transactional annotation 속성 전파 propagation

by Developer RyanKim 2020. 2. 1.

@Transactional 이란? : https://lion-king.tistory.com/3?category=854359

 

(Spring Boot) @Transactional 이란? / @Transactional에 대하여

@Transactional StackOverflow 질문중 UserNameNotFoundException 발생시 delete method가 실행되지않는다는 질문에 답을 하였습니다. https://stackoverflow.com/questions/52619924/how-to-execute-transaction..

lion-king.tistory.com

이전글과 이어서 @Transactional을 사용할 때 고려해야 할 속성들에 대해 알아보겠습니다.

  * Propagation (= 전파) : 트랜잭션의 전파 유형을 설정하는 속성

org.springframework.transaction.annotation 패키지의 Enum Propagation

더보기
package org.springframework.transaction.annotation;

import org.springframework.transaction.TransactionDefinition;

/**
* Enumeration that represents transaction propagation behaviors for use
* with the {@link Transactional} annotation, corresponding to the
* {@link TransactionDefinition} interface.
*
* @author Colin Sampaleanu
* @author Juergen Hoeller
* @since 1.2
*/
public enum Propagation {

/**
* Support a current transaction, create a new one if none exists.
* Analogous to EJB transaction attribute of the same name.
* <p>This is the default setting of a transaction annotation.
*/
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

/**
* Support a current transaction, execute non-transactionally if none exists.
* Analogous to EJB transaction attribute of the same name.
* <p>Note: For transaction managers with transaction synchronization,
* {@code SUPPORTS} is slightly different from no transaction at all,
* as it defines a transaction scope that synchronization will apply for.
* As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
* will be shared for the entire specified scope. Note that this depends on
* the actual synchronization configuration of the transaction manager.
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
*/
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

/**
* Support a current transaction, throw an exception if none exists.
* Analogous to EJB transaction attribute of the same name.
*/
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

/**
* Create a new transaction, and suspend the current transaction if one exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available to it (which is server-specific in standard Java EE).
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

/**
* Execute non-transactionally, suspend the current transaction if one exists.
* Analogous to EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available to it (which is server-specific in standard Java EE).
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

/**
* Execute non-transactionally, throw an exception if a transaction exists.
* Analogous to EJB transaction attribute of the same name.
*/
NEVER(TransactionDefinition.PROPAGATION_NEVER),

/**
* Execute within a nested transaction if a current transaction exists,
* behave like {@code REQUIRED} otherwise. There is no analogous feature in EJB.
* <p>Note: Actual creation of a nested transaction will only work on specific
* transaction managers. Out of the box, this only applies to the JDBC
* DataSourceTransactionManager. Some JTA providers might support nested
* transactions as well.
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
*/
NESTED(TransactionDefinition.PROPAGATION_NESTED);


private final int value;


Propagation(int value) {
this.value = value;
}

public int value() {
return this.value;
}

}


- 전파유형의 종류와 설정에 따른 테스트 코드의 실행 로그
* 테스트코드 예시

@RunWith(SpringRunner.class)
@SpringBootTest
public class TransTest {

    @Autowired
    Parent parent;


    @Test
    // 테스트 메소드가 트랜잭션을 생성하지 않도록
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void transactional_propagation_test() {
        System.out.println("--transactional_propagation_test--");
        parent.parentMethod();
    }

}

@Component
public class Parent {

    @Autowired
    Called called;


    @Transactional
    public void parentMethod() {
        System.out.println("I'm parent");
        called.calledMethod();
    }
}

@Component
public class Called {

    @Transactional(propagation = ?)
    public void calledMethod() {
        System.out.println("I'm called");
    }
}

 

1. PROPAGATION_REQUIRED ( JpaTransactionManager Default )

부모 트랜잭션이 존재할 경우 부모 트랜잭션에 참여한다.

부모 트랜잭션이 없을 경우 새 트랜잭션을 시작한다.
일반적으로 사용되는 트랜잭션의 전파유형이다.

 

- 테스트 코드 결과
parentMethod: @Transactional  // default- PROPAGATION_REQUIRED

calledMethod: @Transactional  // default- PROPAGATION_REQUIRED

더보기

Participating in existing transaction 확인

 

parentMethod: @Transactional(propagation = Propagation.NOT_SUPPORTED)

calledMethod: @Transactional  // default- PROPAGATION_REQUIRED

더보기

새 트랜잭션 생성 확인

 

2. PROPAGATION_SUPPORTS

부모 트랜잭션이 존재할 경우 부모 트랜잭션에 참여한다.

부모 트랜잭션이 없을 경우 non-transactional 하게 동작한다.

 

- 테스트 코드 결과
parentMethod: @Transactional  // default- PROPAGATION_REQUIRED

calledMethod: @Transactional(propagation = Propagation.SUPPORTS)

더보기

Participating in existing transaction 확인

 

parentMethod: @Transactional(propagation = Propagation.NOT_SUPPORTED)

calledMethod: @Transactional(propagation = Propagation.SUPPORTS)

더보기

트랜잭션 생성 안함

 

3. PROPAGATION_MANDATORY

부모 트랜잭션이 존재할 경우 부모 트랜잭션에 참여한다.

부모 트랜잭션이 없을 경우 Exception이 발생한다.

 

- 테스트 코드 결과
parentMethod: @Transactional  // default- PROPAGATION_REQUIRED

calledMethod: @Transactional(propagation = Propagation.MANDATORY)

더보기

Participating in existing transaction 확인

 

 

 

parentMethod: @Transactional(propagation = Propagation.NOT_SUPPORTED)

calledMethod: @Transactional(propagation = Propagation.MANDATORY)

더보기

Exception이 발생

 

 

4. PROPAGATION_REQUIRES_NEW

부모 트랜잭션 유무에 상관없이 새 트랜잭션을 시작한다.

부모 트랜잭션이 존재할 경우 부모 트랜잭션을 중지 시킨다.

 

- 테스트 코드 결과
parentMethod: @Transactional  // default- PROPAGATION_REQUIRED

calledMethod: @Transactional(propagation = Propagation.REQUIRES_NEW)

더보기

parentMethod calledMethod 모두 트랜잭션 생성

 

 

parentMethod: @Transactional(propagation = Propagation.NOT_SUPPORTED)

calledMethod: @Transactional(propagation = Propagation.REQUIRES_NEW)

더보기

calledMethod 트랜잭션 생성

 

 

5. PROPAGATION_NOT_SUPPORTED

부모 트랜잭션 유무에 상관없이 non-transactional 하게 동작한다.

부모 트랜잭션이 존재할 경우 부모 트랜잭션을 중지 시킨다.

 

- 테스트 코드 결과
parentMethod: @Transactional  // default- PROPAGATION_REQUIRED

calledMethod: @Transactional(propagation = Propagation.NOT_SUPPORTED)

더보기

parentMethod 만 트랜잭션 생성 후 중단 및 재시작 확인

 

 

parentMethod: @Transactional(propagation = Propagation.NOT_SUPPORTED)

calledMethod: @Transactional(propagation = Propagation.NOT_SUPPORTED)

더보기

트랜잭션 생성안함

 

 

6. PROPAGATION_NEVER

항상 non-transactional 하게 동작하며 부모 트랜잭션이 존재할 경우 Exception이 발생한다.

 

- 테스트 코드 결과
parentMethod: @Transactional  // default- PROPAGATION_REQUIRED

calledMethod: @Transactional(propagation = Propagation.NEVER)

더보기

Exception이 발생

 

 

parentMethod: @Transactional(propagation = Propagation.NOT_SUPPORTED)

calledMethod: @Transactional(propagation = Propagation.NEVER)

더보기

Exception이 발생하지 않고 트랜잭션 생성하지 않음

 

 

 

7. PROPAGATION_NESTED (  JpaTransactionManager 에서 지원하지 않음 )

부모 트랜잭션과 독립적으로 롤백되거나 커밋 될 수 있다.
부모 트랜잭션이 존재하지 않는다면 PROPAGATION_REQUIRED 처럼 동작
PROPAGATION_REQUIRES_NEW 와 차이점은 새 트랜잭션을 생성하지 않고
여러개의 save point를 가지는 단일 트랜잭션을 사용하며, 부모 트랜잭션에 영향을 받을 수 있다는 것이다.

 

----------

더보기

Exception 발생. 지원하지 않음.

 

여기까지 @Transactional propagation 옵션 종류 및 테스트 결과에 대하여 알아보았습니다.
위 옵션들로 트랜잭션 경계를 설정하여 개발에 적용이 가능합니다.

By Ryankim

댓글