728x90
반응형
스프링에서 트랜잭션을 분리하고 싶을 때, @Transactional(propagation = Propagation.REQUIRES_NEW)로 트랜잭션을 분리하고자 하는 메서드에 어노테이션을 달아주면된다. 이외에도 @Transactional을 분리하는 종류에 대해서는 이전에 정리했었다.
[TIL][링크] 트랜잭션의 전파, Spring @Transactional 중첩
그러나 이때, 트랜잭션을 분리하고자 하는 메서드를 반드시 클래스를 분리해서 적용해야한다. 이것은 @Transactional 어노테이션이 Spring의 CGLIB Proxy를 기반으로 동작하기 때문이다. 다시 말해 동일한 Bean으로 등록된 클래스의 메서드에서는 @Transactional을 단일 건으로 취급한다. Proxy로 불러온 빈은 다른 클래스가 아닌 경우 인터셉트되어 전달되지 않기 때문에 @Transactional이 동작하지 않는다.
트랜잭션이 분리될 것으로 예상하지만, 실제로는 분리되지 않는 코드
public class saveService(XxxEntity xxxEntity) {
//...
@Transactional
public void totalSave(XxxEntity xxxEntity) {
//save 로직
//savePart1(xxxEntity);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void savePart1(XxxEntity xxxEntity) {
//savePart1 로직 - xxxEntity 이용
}
}
(경험상 기록 내용)
또한 프록시 객체로 불러온 Entity 등은 클래스를 분리하더라도 정상적인 동작이 되지 않을 수 있다. 따라서 id 값 등을 이용하여 Repository를 통해 DB에서 다시 객체를 조회하였다. 아마 이것도 Entity를 프록시 객체 형태로 가져오면 캐시에 저장된 값들을 가져올뿐, DB에 접근하여 SQL문을 commit은 하지 않기 때문인 것 같다.
트랜잭션 정상 분리 코드 : 클래스를 분리
public class saveService(XxxEntity xxxEntity) {
//...
@Transactional
public void totalSave(XxxEntity xxxEntity) {
//save 로직
//변경 : xxxEntity의 id값 전달
//savePart1(xxxEntity.getId());
}
}
public class savePart1Service(Long xxxId) {
//...
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void savePart1(Long id) {
//추가 : DB 접근하여 entity 재조회
XxxEntity xxxEntity = xxxRepository.findById(id).orElseThrow(.....);
//savePart1 로직 실행
}
}
참조
1. popit - 동일한 Bean(Class)에서 @Transactional 동작 방식
728x90
반응형
'Programming-[Backend] > Spring' 카테고리의 다른 글
[TIL] Spring Java GC, OOM, JVM Heap dump - Memory Analyzer, pmd (0) | 2024.08.30 |
---|---|
[탐험][자바 스프링 Http 통신하기] 1. URL Connection (0) | 2022.06.01 |
[TIL]PageableDefault는 non-deterministic sort를 한다 (0) | 2022.04.04 |
[링크][탐험][작성중] WebMvcConfigurer, WebMvcConfigurationSupport, @EnableWebMvc (0) | 2022.03.03 |
[링크] 스프링 AOP 용어 개념 정리 (0) | 2022.02.27 |