@Transactional 안에 @Transactional 이 있는 경우 테스트를 해보았습니다.
TransactionSynchronizationManager.*isActualTransactionActive*() 메서드를 이용해서 트랜잭션이 적용되는지 확인 할 수 있습니다.
1. ### 외부메서드(트랜잭션) + 이너메서드
@Slf4j
@Service
public class TransactionService {
@Transactional
public void outerMethod() {
log.info(" ****** outerMethod start ******");
log.info(" ****** outerMethod transaction Active : {}" ,
TransactionSynchronizationManager.isActualTransactionActive());
innerMethod();
log.info(" ****** outerMethod end ******");
}
public void innerMethod() {
log.info(" ****** innerMethod start ******");
log.info(" ****** innerMethod transaction Active : {}" ,
TransactionSynchronizationManager.isActualTransactionActive());
log.info(" ****** innerMethod end ******");
}
}
@Test
@DisplayName("외부 메서드(트랜잭션) + 내부 메서드")
void test() {
transactionService.outerMethod();
}
//테스트 결과
****** outerMethod start ******
****** outerMethod transaction Active : true
****** innerMethod start ******
****** innerMethod transaction Active : true
****** innerMethod end ******
****** outerMethod end ******
2. ### 외부메서드 + 이너메서드(트랜잭션)
해당 테스트를 진행할 경우, 인텔리제이에서 아래와 같은 경고 표시를 나타내줍니다.
@Slf4j
@Service
public class TransactionService {
public void outerMethod() {
log.info(" ****** outerMethod start ******");
log.info(" ****** outerMethod transaction Active : {}" ,
TransactionSynchronizationManager.isActualTransactionActive());
innerMethod();
log.info(" ****** outerMethod end ******");
}
@Transactional
public void innerMethod() {
log.info(" ****** innerMethod start ******");
log.info(" ****** innerMethod transaction Active : {}" ,
TransactionSynchronizationManager.isActualTransactionActive());
log.info(" ****** innerMethod end ******");
}
}
@Test
@DisplayName("외부 메서드 + 내부 메서드(트랜잭션)")
void test() {
transactionService.outerMethod();
}
// 테스트 결과
****** outerMethod start ******
****** outerMethod transaction Active : false
****** innerMethod start ******
****** innerMethod transaction Active : false
****** innerMethod end ******
****** outerMethod end ******
3. ### 외부메서드 + 다른클래스의 이너메서드(트랜잭션)
다른 클래스의 메서드에 @Transactional 을 적용시키고 사용하면 해당 메서드는 트랜잭션이 적용된다.
@Slf4j
@Service
public class OtherService {
@Transactional
public void otherInnerMethod() {
log.info(" ****** outer innerMethod start ******");
log.info(" ****** outer innerMethod transaction Active : {}" ,
TransactionSynchronizationManager.isActualTransactionActive());
log.info(" ****** outer innerMethod end ******");
}
}
@Slf4j
@Service
@RequiredArgsConstructor
public class TransactionService {
private final OtherService otherService;
public void outerMethod() {
log.info(" ****** outerMethod start ******");
log.info(" ****** outerMethod transaction Active : {}" ,
TransactionSynchronizationManager.isActualTransactionActive());
otherService.otherInnerMethod();
log.info(" ****** outerMethod end ******");
}
@Test
@DisplayName("외부 메서드 + 다른 클래스 내부 메서드(트랜잭션)")
void test() {
transactionService.outerMethod();
}
// 테스트 결과
****** outerMethod start ******
****** outerMethod transaction Active : false
****** outer innerMethod start ******
****** outer innerMethod transaction Active : true
****** outer innerMethod end ******
****** outerMethod end ******
4. ### 외부 메서드(트랜잭션) + 다른 클래스 내부 메서드
@Slf4j
@Service
public class OtherService {
public void otherInnerMethod() {
log.info(" ****** outer innerMethod start ******");
log.info(" ****** outer innerMethod transaction Active : {}" ,
TransactionSynchronizationManager.isActualTransactionActive());
log.info(" ****** outer innerMethod end ******");
}
}
@Slf4j
@Service
@RequiredArgsConstructor
public class TransactionService {
private final OtherService otherService;
@Transactional
public void outerMethod() {
log.info(" ****** outerMethod start ******");
log.info(" ****** outerMethod transaction Active : {}" ,
TransactionSynchronizationManager.isActualTransactionActive());
otherService.otherInnerMethod();
log.info(" ****** outerMethod end ******");
}
}
@Test
@DisplayName("외부 메서드(트랜잭션) + 다른 클래스 내부 메서드")
void test() {
transactionService.outerMethod();
}
// 결과
****** outerMethod start ******
****** outerMethod transaction Active : true
****** outer innerMethod start ******
****** outer innerMethod transaction Active : true
****** outer innerMethod end ******
****** outerMethod end ******
## 정리
- @Transactional 은 AOP 를 사용하여 구현된다.
- 트랜잭션은 객체 외부에서 처음 진입하는 메서드를 기준으로 동작한다. ( AOP Proxy는 호출시점에 target을 가로챈다 )
- private 메서드에서는 작동되지 않는다.
- 기본적으로 CGLib 을 사용한다 ( 인터페이스가 있으면 동적 Proxy 사용 )
- 외부에서 @Transactional 이 적용되지 않다면 내부 이너메서드에 적용이 되어있더라도 적용되지 않는다.
- 이너메서드에 적용시키고 싶으면, 다른 클래스를 만들어 사용해야 한다.
- @Transactional 의 전파속성의 기본속성은 REQURED 이다 ( 진행중인 트랜잭션 내부에 새로운 트랜잭션이 들어오면 기존 트랜잭션이 참여 )
'Spring > Spring-detail' 카테고리의 다른 글
동시성 문제 해결 - Synchronized, Pessimistic Lock, Optimistic Lock, Redis (0) | 2024.04.08 |
---|---|
@Conditional 을 이용해 특정 조건일 때만 사용 (0) | 2024.02.22 |
@ConfigurationProperties / @ConfigurationPropertiesBean (0) | 2023.08.23 |
JAVA 싱글톤, Spring 싱글톤에 대해. (0) | 2023.03.23 |
Jar 파일에 대해 (0) | 2023.03.01 |
댓글