(Spring/Spring Boot) transactional annotation 속성 전파 propagation
@Transactional 이란? : https://lion-king.tistory.com/3?category=854359
이전글과 이어서 @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 발생. 지원하지 않음.