그 전에는 트랜잭션 템플릿을 사용했다. 트랜잭션 템플릿을 사용해서 반복되는 트랜잭션 관련 코드를 줄일 수 있었고 코드가 보다 간결하고 효율적이게 바뀌는 것을 확인할 수 있었다.
트랜잭션 템플릿 사용 코드
하지만 이 코드에서도 개선해야할 문제점은 있다. 바로 서비스 로직 안에 트랜잭션 코드와 서비스 로직 코드가 한 군데에 섞여 있다는 점이다.
비즈니스 로직은 변경가능성이 있기 때문에 나중에 유지보수를 할 때에도 이렇게 트랜잭션 코드와 비즈니스 로직 코드가 한군데에 섞여 있는 것은 비효율 적이라고 할 수 있다. 그렇다면 어떤 방법으로 이 두 코드를 분리할 수 있을까?
트랜잭션 코드와 비즈니스 로직을 분리하기 위해 프록시를 도입해보자.
스프링에서 만들어주는 프록시를 사용하면 트랜잭션 프록시가 트랜잭션 처리 로직을 모두 수행하고 실제 서비스 로직을 대신 호출한다. 이렇게 트랜잭션 프록시를 사용하면 순수한 비즈니스 로직만 따로 분리할 수 있다.
클라이언트에서 트랜잭션 프록시를 호출하면 트랜잭션 프록시에서 서비스를 호출하고 다시 트랜잭션 프록시에서 트랜잭션을 종료한다. 이렇게 프록시를 사용하면 트랜잭션을 처리하는 객체와 서비스 로직을 명확하게 분리할 수 있다.
스프링은 트랜잭션 AOP를 처리하기 위한 모든 기능을 제공하는데 스프링 부트를 사용하면 트랜잭션 AOP를 처리하기 위해 필요한 스프링 빈들도 자동으로 등록해준다. 따라서 개발자는 트랜잭션 처리가 필요한 곳에 @Transactional 애노테이션만 붙여주면 된다. 이 애노테이션을 붙여주면 스프링이 자동으로 이 애노테이션을 인식해서 트랜잭션 프록시를 적용해준다.
import org.springframework.transaction.annotation.Transactional;
@Transactional
public void transfer(String fromId, String toId, int money) throws Exception {
bzLogic(fromId,toId, money);
}
비즈니스 관련 로직 외에 트랜잭션 관련 코드는 전부 제거하고 @Transactional 애노테이션만 붙이면 끝난다. @Transactional 애노테이션은 클래스나 메서드에 붙이면 된다.
클래스에 @Transactional 사용
@Transactional
public class serviceExample {
//트랜잭션 관련 코드 제거
private final MemberRepository memberRepository;
public MemberServiceV(MemberRepository3 memberRepository) {
this.memberRepository = memberRepository;
}
public void transfer(String fromId, String toId, int money) throws Exception {
bzLogic(fromId,toId, money );
}
public class TransactionProxy {
private MemberService target;
public void logic() {
//트랜잭션 시작
TransactionStatus status = transactionManager.getTransaction(..);
try {
//실제 대상 호출
target.logic();
transactionManager.commit(status); //성공시 커밋
} catch (Exception e) {
transactionManager.rollback(status); //실패시 롤백
throw new IllegalStateException(e);
}
}
}
@Transactional 애노테이션을 붙이면 스프링에서 서비스 로직을 상속받아서 위의 코드와 같은 프록시 클래스를 만들어낸다.
테스트코드로 직접 service 객체를 확인해보면 CGLIB 라이브러리를 통해서 프록시가 적용된 것을 확인할 수 있다. 이제 개발자는 트랜잭션 관련 코드를 직접 작성하지 않아도 스프링의 도움을 받아 @Transactional 애노테이션으로 간단하게 트랜잭션과 서비스 로직을 분리하는 코드를 작성할 수 있다.
이 글은 김영한님의 스프링 DB 1편 - 데이터 접근 핵심 원리 강의를 듣고 정리한 내용입니다.