개발기록

Spring의 프록시 기반 트랜잭션 관리 본문

Spring

Spring의 프록시 기반 트랜잭션 관리

Danuvibe 2024. 9. 9. 23:05

Spring 프레임워크는 선언적 트랜잭션 관리를 위해 프록시 기반의 접근 방식을 사용합니다. 이 방식은 개발자가 비즈니스 로직에 집중할 수 있게 하면서도 강력한 트랜잭션 관리 기능을 제공합니다.

1. 프록시란?

프록시는 실제 객체를 감싸는 래퍼(wrapper) 객체입니다. 클라이언트는 프록시를 통해 실제 객체와 상호작용하며, 프록시는 실제 객체에 대한 접근을 제어하거나 부가 기능을 추가할 수 있습니다.

2. Spring의 트랜잭션 프록시 작동 원리

  1. 프록시 생성: Spring은 @Transactional 어노테이션이 붙은 빈에 대해 프록시를 생성합니다.

  2. 메서드 호출 가로채기: 클라이언트가 빈의 메서드를 호출하면, 실제로는 프록시의 메서드가 호출됩니다.

  3. 트랜잭션 시작: 프록시는 트랜잭션 관리자를 사용하여 트랜잭션을 시작합니다.

  4. 실제 메서드 호출: 프록시는 실제 객체의 메서드를 호출합니다.

  5. 트랜잭션 완료: 메서드 실행이 완료되면, 프록시는 트랜잭션을 커밋하거나 롤백합니다.

3. 프록시 생성 방식

Spring은 두 가지 방식으로 프록시를 생성합니다:

  1. JDK 동적 프록시: 인터페이스를 구현한 클래스에 대해 사용됩니다.
  2. CGLIB 프록시: 인터페이스가 없는 클래스에 대해 사용됩니다.

4. 프록시 기반 트랜잭션 관리의 장점

  1. 비침투성: 비즈니스 로직에 트랜잭션 관리 코드가 섞이지 않습니다.
  2. 재사용성: 트랜잭션 로직을 여러 빈에서 재사용할 수 있습니다.
  3. 유연성: 트랜잭션 속성을 쉽게 변경할 수 있습니다.

5. 프록시 작동 예시

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void createUser(User user) {
        userRepository.save(user);
        // 다른 작업...
    }
}

이 코드에서 실제 실행 흐름은 다음과 같습니다:

  1. 클라이언트가 userService.createUser(user)를 호출합니다.
  2. 호출은 Spring이 생성한 프록시 객체로 전달됩니다.
  3. 프록시는 트랜잭션을 시작합니다.
  4. 프록시는 실제 UserService 객체의 createUser 메서드를 호출합니다.
  5. 메서드 실행이 완료되면, 프록시는 트랜잭션을 커밋하거나 예외 발생 시 롤백합니다.

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. 프록시 기반 트랜잭션 관리의 주의사항

  1. self-invocation 문제: 같은 클래스 내에서 @Transactional 메서드를 호출할 때 프록시가 동작하지 않습니다.

  2. 프록시 내부 호출: 프록시 내부에서 다른 @Transactional 메서드를 호출할 때, 새로운 트랜잭션이 시작되지 않을 수 있습니다.

  3. private 메서드: @Transactional을 private 메서드에 사용할 수 없습니다. 프록시가 이를 가로챌 수 없기 때문입니다.

Comments