-
Notifications
You must be signed in to change notification settings - Fork 0
김준기 6주차 학습 일지
스프링 트랜잭션 내용을 학습해야할 필요가 있어서, 6주차에는 해당 내용 위주로 학습을 진행했습니다.
@Transactional
AOP가 제대로 적용되고 있는지 확인하는 방법을 알아본다.
TransactionSynchronizationManager
추상 클래스의 isActualTransactionActive()
메서드로 트랜잭션 적용 여부를 확인할 수 있다. 현재 스레드에 트랜잭션이 적용되어 있는지 확인할 수 있는 기능이다.
@Slf4j
@Service
public class BasicService {
@Transactional
public void tx() {
log.info("call tx");
boolean txActive = TransactionSynchronizationManager.isActualTransactionActive();
log.info("tx active = {}", txActive);
}
}
@Test
@DisplayName("트랜잭션 AOP 적용 여부는 TransactionSynchronizationManager.isActualTransactionActive()로 확인할 수 있다")
void txTest() {
basicService.tx();
}
현재 스레드에 트랜잭션이 적용되어 있는지 확인하는 기능이므로, 아래와 같이 테스트 코드 내에서 확인하는 방법도 생각해볼 수도 있겠다. 하지만 트랜잭션은 기본적으로 테스트에 전파되지 않으므로, 원하는 결과값인 true가 아니라 false로 출력된다.
@Test
@DisplayName("트랜잭션 AOP 적용 여부는 TransactionSynchronizationManager.isActualTransactionActive()로 확인할 수 있다")
void txTest() {
basicService.tx();
boolean txActive = TransactionSynchronizationManager.isActualTransactionActive();
log.info("tx active = {}", txActive);
}
@Transactional
애노테이션이 클래스 또는 메서드 레벨에 기재되어 있는 경우, 스프링은 해당 클래스를 프록시로 관리하여 스프링 빈으로 등록한다. 이 과정에 대한 전반적 흐름에 대해 살펴본다.
-
@Transactional
애노테이션이 클래스나 메서드에 하나라도 있으면, 해당 클래스에 대한 가짜 객체를 만들어서 스프링 컨테이너에 등록한다. -
만약 클래스가
xxxService
라면,xxxService$$CGLIB
인스턴스(이하 프록시 객체)를 생성해서 스프링 빈에 등록하는 것이다. -
@Autowired
에 의한 의존 관계 주입도 프록시 객체가 주입되는 것이다. -
프록시 객체는
xxxService
를 상속하고 있다. 즉, 상속받은 기능을 그대로 사용할 수 있으므로 아래와 같은 구조가 가능해진다.// pseudo-code public void xxxService$$CGLIB extends xxxService { @Transactional public void bizMethod1() { tx.start(); bizMethod1(); // xxxService의 실제 메서드 호출 tx.end(); } public void bizMethod2() { bizMethod2(); // xxxService의 실제 메서드 호출 } }
@Transactional
이 메서드 레벨에 적용되어 있는 경우, 애노테이션 유무에 따라 트랜잭션을 적용한다.
@Transactional
적용 위치에 따른 우선순위를 확인한다.
@Transactional
은 readOnly
옵션 이 있다. 클래스 레벨에 적용된 애노테이션은 true, 메서드 레벨에 적용된 애노테이션이 false라면 후자가 우선순위를 가진다. 톰캣, 스프링 등을 살펴보면 일반적으로 더 구체적이고 자세한 것이 우선순위를 가진다. @Transactional
여부를 메서드 레벨에서 먼저 확인하여 적용하고, 없다면 클래스 레벨을 확인하여 적용한다.
@Slf4j
@Transactional(readOnly = true)
static class LevelService {
@Transactional(readOnly = false)
public void write() {
log.info("call write");
printTxInfo();
}
public void read() {
log.info("call read");
printTxInfo();
}
private void printTxInfo() {
boolean txActive = TransactionSynchronizationManager.isActualTransactionActive();
log.info("txActive: {}", txActive);
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
log.info("readOnly: {}", readOnly);
}
}
@Test
@DisplayName("트랜잭션 readOnly 옵션은 TransactionSynchronizationManager.isCurrentTransactionReadOnly()로 확인할 수 있다")
void orderTest() {
service.write(); // readOnly: false
service.read(); // readOnly: true
}
스프링 DB 2편 - 데이터 접근 활용 기술 - Sesction 9