개발기록
Spring의 프록시 기반 트랜잭션 관리 본문
Spring 프레임워크는 선언적 트랜잭션 관리를 위해 프록시 기반의 접근 방식을 사용합니다. 이 방식은 개발자가 비즈니스 로직에 집중할 수 있게 하면서도 강력한 트랜잭션 관리 기능을 제공합니다.
1. 프록시란?
프록시는 실제 객체를 감싸는 래퍼(wrapper) 객체입니다. 클라이언트는 프록시를 통해 실제 객체와 상호작용하며, 프록시는 실제 객체에 대한 접근을 제어하거나 부가 기능을 추가할 수 있습니다.
2. Spring의 트랜잭션 프록시 작동 원리
프록시 생성: Spring은
@Transactional어노테이션이 붙은 빈에 대해 프록시를 생성합니다.메서드 호출 가로채기: 클라이언트가 빈의 메서드를 호출하면, 실제로는 프록시의 메서드가 호출됩니다.
트랜잭션 시작: 프록시는 트랜잭션 관리자를 사용하여 트랜잭션을 시작합니다.
실제 메서드 호출: 프록시는 실제 객체의 메서드를 호출합니다.
트랜잭션 완료: 메서드 실행이 완료되면, 프록시는 트랜잭션을 커밋하거나 롤백합니다.
3. 프록시 생성 방식
Spring은 두 가지 방식으로 프록시를 생성합니다:
- JDK 동적 프록시: 인터페이스를 구현한 클래스에 대해 사용됩니다.
- CGLIB 프록시: 인터페이스가 없는 클래스에 대해 사용됩니다.
4. 프록시 기반 트랜잭션 관리의 장점
- 비침투성: 비즈니스 로직에 트랜잭션 관리 코드가 섞이지 않습니다.
- 재사용성: 트랜잭션 로직을 여러 빈에서 재사용할 수 있습니다.
- 유연성: 트랜잭션 속성을 쉽게 변경할 수 있습니다.
5. 프록시 작동 예시
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void createUser(User user) {
userRepository.save(user);
// 다른 작업...
}
}
이 코드에서 실제 실행 흐름은 다음과 같습니다:
- 클라이언트가
userService.createUser(user)를 호출합니다. - 호출은 Spring이 생성한 프록시 객체로 전달됩니다.
- 프록시는 트랜잭션을 시작합니다.
- 프록시는 실제 UserService 객체의
createUser메서드를 호출합니다. - 메서드 실행이 완료되면, 프록시는 트랜잭션을 커밋하거나 예외 발생 시 롤백합니다.
6. 트랜잭션 프록시의 내부 동작
프록시의 내부 동작을 의사 코드로 표현하면 다음과 같습니다:
public class TransactionalProxy extends UserService {
private UserService target; // 실제 UserService 객체
private PlatformTransactionManager transactionManager;
@Override
public void createUser(User user) {
TransactionStatus status = null;
try {
status = transactionManager.getTransaction(new DefaultTransactionDefinition());
// 실제 메서드 호출
target.createUser(user);
// 트랜잭션 커밋
transactionManager.commit(status);
} catch (RuntimeException ex) {
// 예외 발생 시 롤백
transactionManager.rollback(status);
throw ex;
}
}
}
7. 프록시 기반 트랜잭션 관리의 주의사항
self-invocation 문제: 같은 클래스 내에서 @Transactional 메서드를 호출할 때 프록시가 동작하지 않습니다.
프록시 내부 호출: 프록시 내부에서 다른 @Transactional 메서드를 호출할 때, 새로운 트랜잭션이 시작되지 않을 수 있습니다.
private 메서드: @Transactional을 private 메서드에 사용할 수 없습니다. 프록시가 이를 가로챌 수 없기 때문입니다.

'Spring' 카테고리의 다른 글
| @Configuration은 어떻게 싱글톤 빈을 보장하는가? (0) | 2024.09.10 |
|---|---|
| Spring AOP 내부 호출 문제 해결 방법 (0) | 2024.09.10 |
| JPQL 벌크 연산을 통한 더티 체킹 우회 (0) | 2024.09.09 |
| JPA 더티 체킹의 성능 이슈와 최적화 전략 (0) | 2024.09.09 |
| 데이터베이스 언두 로그(Undo Log) & Transaction(readOnly=true) (0) | 2024.09.09 |