트랜잭션 시작, 비즈니스 로직 실행, 트랜잭션 종료(성공시 커밋, 예외 발생시 롤백)하는 코드가 반복
되는 문제 발생
템플릿 콜백 패턴
을 통해 이런 문제를 해결할 수 있는데, 스프링은 TransactionTemplate
이라는 템플릿 클래스를 제공함
@Slf4j
public class MemberServiceV3_2 {
// private final PlatformTransactionManager transactionManager;
private final TransactionTemplate txTemplate;
private final MemberRepositoryV3 memberRepository;
public MemberServiceV3_2(final PlatformTransactionManager transactionManager, final MemberRepositoryV3 memberRepository) {
txTemplate = new TransactionTemplate(transactionManager); //트랜잭션 템플릿은 클래스, 트랜잭션 매니저는 인터페이스
this.memberRepository = memberRepository;
}
public void accountTransfer(String fromId, String toId, int money) throws SQLException {
txTemplate.executeWithoutResult(status -> {
try {
bizLogic(fromId, toId, money);
} catch (SQLException e) {
throw new IllegalStateException(e);
}
});
}
...
}
비즈니스 로직이 정상 수행되면 커밋하고, unchecked exception
이 발생하면 롤백함
반복 코드는 제거되었지만 서비스 로직에 트랜잭션 처리 로직이 들어가고, SRP
에 위배됨
서비스 입장에서 비즈니스 로직은 핵심 기능이고, 트랜잭션은 부가 기능임 -> 이를 AOP
를 사용해서 따로 개발할 수 있음
트랜잭션 프록시
를 도입
트랜잭션 프록시가 트랜잭션 처리 로직을 모두 가져가고 트랜잭션 시작 후 타겟 객체의 메서드를 대신 호출함으로써 서비스 계층에는 순수 비즈니스 로직만 남길 수 있음
스프링에서는 @Transactional
어노테이션만 붙이면 트랜잭션 프록시를 적용해 줌
@Transactional
은 메서드, 클래스에 모두 붙일 수 있는데, 클래스에 붙이는 경우 public
메서드가 AOP
적용 대상이 됨
스프링 부트는 DataSource
와 PlatformTransactionManager
를 자동으로 등록해 줌
DataSource
dataSource
라는 이름으로 빈 등록
개발자가 직접 DataSource
빈을 등록하면 스프링 부트는 빈을 자동으로 등록하지 않음
application.properties
(또는 application.yml
)에 있는 속성을 사용해서 DataSource
생성
기본으로 생성하는 DataSource
는 HikariDataSource
(관련 설정은 spring.datasource.hikari.*
와 같이 수행)
spring.datasource.url
속성이 없으면 embedded database
를 띄움
PlatformTransactionManager
transactionManager
라는 이름으로 빈 등록
DataSource
와 마찬가지로 개발자가 직접 등록하면 자동 등록하지 않음
등록된 라이브러리를 기반으로 구현체를 선택함 (JdbcTransactionManager
, JpaTransactionManager
등)