Hello

[spring] 같은 bean에서 Propagation.REQUIRES_NEW 동작하지 않음 본문

spring

[spring] 같은 bean에서 Propagation.REQUIRES_NEW 동작하지 않음

nari0_0 2024. 1. 29. 17:18
728x90

 

master, slave 환경의 DB를 사용하고 있어 RoutingDataSource를 구현해 readOnly일 때 slave를 바라볼 수 있도록 사용하고 있습니다.

 

아래처럼 otherService가 호출 되었을 때, 각각의 트랜잭션으로 동작할 것을 기대했으나 SQL Error: "1290," SQLState: HY000 에러를 만나게 되었습니다.

getOne에서 열린 트랜잭션에 포함되어 save메소드가 동작해 에러가 발생한 것입니다. @Transactional은 AOP 프록시를 생성합니다. 같은 빈에서 @Transactional이 붙은 메소드를 여러개 호출 시 최초 호출 되는 메소드의 옵션으로 프록시가 생성됩니다.

아래를 코드는 readOnly 옵션으로 트랜잭션이 활성 된 후 해당 트랜잭션에 save 메소드 동작이 참여하게 됩니다.

@Service
public class ExampleService {
    @Autowired
    private SimpleService simpleSevice;
    @Autowired
    private OtherService otherService;

    public void someLogic(Integer id, SimpleRequest form) {
    	... 
        Other other = otherService.getOne(id);
        ...
        otherService.save(other);
    }
}

@Service
public class OtherService {
    @Autowired
    private OtherRepo otherRepo;
 
    @Transactional(readOnly = true)
    public Other getOne(Integer id){
        return otherRepo.findById(id).orElseThrow(() -> new RuntimeException("not found other"));
    } 
 
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void save(Other other) {
    	simpleRepo.save();
    }
}

 

after

OtherService.save 메소드 내에서 getOne을 호출하도록 로직 수정해 해결했습니다.

불필요해진 propagation 옵션 또한 제거.

@Service
public class ExampleService {
    @Autowired
    private SimpleService simpleSevice;
    @Autowired
    private OtherService otherService;

    public void someLogic(Integer id, SimpleRequest form) {
        ...
        otherService.save();
    }
}

@Service
public class OtherService {
    @Autowired
    private OtherRepo otherRepo;
 
    @Transactional(readOnly = true)
    public Other getOne(Integer id){
        return otherRepo.findById(id).orElseThrow(() -> new RuntimeException("not found other"));
    } 
 
    @Transactional
    public void save() {
    	Other other = getOne(id);
        ...
    	simpleRepo.save();
    }
}

 

 트랜잭션 프록시에서 메서드 호출

프록시를 사용해 트랜잭션을 생성해 사용하는 것을 볼 수 있다.

spring transaction docs

@Transactional docs

참고 :

https://stackoverflow.com/questions/28480480/propagation-requires-new-does-not-create-a-new-transaction-in-spring-with-jpa

728x90