DHistory
[Spring] Self-Invocation? 본문
Question
Spring @Transactional이 같은 클래스 내 메서드 호출 시 트랜잭션이 적용되지 않는 이유는 무엇인가요?
이를 해결하는 방법과 각 방법의 트레이드 오프는 무엇인가요?
Answer 1) @Transactional 동작 과정
> @Transactional은 Spring AOP 프록시 기반으로 동작
> @Transactional은 Proxy 객체 메서드 진입 시 시작
> 같은 클래스 내 this.method()는 Proxy 객체가 아닌 원본 객체를 직접 호출
> this.method() 에 선언된 @Transactional 동작 무시
> 코드 작성 의도와 런타임 시 코드 수행 동작 차이 발생

class PaymentService {
@Transactional
public void processOrder() {
// 트랜잭션이 분리되지 않고 processOrder 트랜잭션과 함께 처리
this.pay()
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void pay() { ... }
}
Answer 2) 외부 클래스로 분리
> 외부 클래스로 분리하여 Proxy 객체 호출
> SRP 원칙을 준수하고 명확하고 테스트 용이
> But. 클래스 증가

Answer 3) AspectJ Weaving 으로 해결 가능 여부
> AspectJ 로 해결이 가능, Bytecode 조작으로 성능 향상 이점 (AOP 적용 시 Reflection, Interceptor Chain 사용)
> But. 빌드 복잡도, 디버깅, 오류 발견 시점 지연 (컴파일 -> 런타임), 팀 러닝커브 증가 문제

Answer 4) Event Publishing으로 Transaction 경계 분리
> DDD, Hexagonal Architecture에서 Application Service Layer 단위가 하나의 Transaction 단위가 되고 내부 도메인 서비스와 분리
> 레이어 경계를 따르면 자연스러운 분리
> But. 내부 이벤트 유실 가능성
> Transactional Outbox Pattern 도입으로 해결 가능
| @EventListener | @TransactionalEventListener | |
| 시점 | 이벤트 발행 즉시 | 트랜잭션 커밋 후 |
| 트랜잭션 관계 | 발행자 트랜잭션에 편승 | 독립적 |
| 롤백 시 | 같이 롤백 | 실행 X |
| 용도 | 같은 트랜잭션에 묶고 싶을 때 | 커밋 확정 후 후처리 |

ETC.
Self Injection @Lazy 기반
> 의도 불명확
class PaymentService(
@Lazy private val self: PaymentService
) {
fun processOrder() {
self.pay()
}
@Transactional
fun pay() { ... }
}
Application Context
> Spring 강결합, 테스트 복잡도 증가
> 의도 불명확, 가독성 저하
class PaymentSerivce(
private val applicationContext: ApplicationContext
) {
fun processOrder() {
val self = applicationConext.getBean(PaymentService:class.java)
self.pay()
}
@Transactional
fun pay() { ... }
}
AopProxy.currentProxy()
> AOP 프레임워크 강결합
> 의도 불명확, 가독성 저하
class PaymentService {
fun processOrder() {
(AopContext.currentProxy() as PaymentService).pay()
}
@Transactional
fun pay() { ... }
}
'Programming > Spring Boot' 카테고리의 다른 글
| [H2] 기본 Data 초기화 (with. JPA) (0) | 2023.10.18 |
|---|---|
| [Spring Boot] DGS 적용하여 GraphQL 사용하기 (0) | 2023.07.05 |
| [Spring Boot] Hello Spring Boot (0) | 2021.09.04 |