2014-01-28 2 views
3

내 서비스 클래스. 내 컨트롤러, 서비스 방법 blockAllDevices에서스프링 트랜잭션 관리 Propagation.REQUIRES_NEW not working

@Service 
@Transactional(value = "transactionManager", readOnly = true, propagation = Propagation.REQUIRED) 
public class DeviceServiceImpl{ 

@Transactional(readOnly = false) 
public void blockAllDevices(){ 

    createSmsDeviceBlock(); 

} 


public void createSmsDeviceBlock(){ 

    addToLogTables(); 

    smsService.sendSms(); 
} 


@Transactional(readOnly = false,propagation = Propagation.REQUIRES_NEW) 
public void addToLogTables(){ 
     try { 
      //save object with DAO methods... 
     } catch (Exception e) { 
      throw new ServiceException(ServiceException.PROCESSING_FAILED, e.getMessage(), e); 
     } 
} 

}

()가 호출하기. addToLogTables() 메소드가 Propergation.REQUIRED_NEW로 표시되었지만 addToLogTables() 메소드에 문제가 발생하여 새 트랜잭션이 생성되지 않고 기존 트랜잭션이 사용 중입니다.

smsService.sendSms() 메소드를 실행하기 전에 addToLogTables() 메소드의 트랜잭션을 커밋해야합니다.

여기 내 문제는 트랜잭션이 커밋되지 않은 경우 addToLogTables() 메서드의 메서드에서 smsService.sendSms() 메서드를 실행하지 않아야합니다.

답변

7

이것은 Propagation.REQUIRES_NEW 호가 아닙니다. 그것은 @Transactional 프록시가 작동하는 방법에 관한 문제입니다.

스프링이 @Transactional으로 주석 처리 된 bean을 프록시 할 때, 기본적으로 프록시 객체에 랩핑하고 트랜잭션을 연 후 위임합니다. 위임 된 호출이 반환되면 프록시는 트랜잭션을 커밋하거나 롤백합니다.

는 예를 들어, 콩은

@Autowired 
private DeviceServiceImpl deviceService; 

봄이 실제로 래퍼 프록시를 주입하는 것입니다.

그래서 당신은 트랜잭션 동작을 가지고있는 프록시의 메소드를 호출하는

deviceService.blockAllDevices(); 

을 수행 할 때. 그러나 blockAllDevices(), 당신은 this 실제 객체가 아닌 프록시를 참조한다, 그래서 트랜잭션 동작이없는 경우 실제로

this.createSmsDeviceBlock(); 

입니다

createSmsDeviceBlock(); 

을 다하고 있습니다.

이 내용은 documentation에서 더 자세히 설명됩니다.

디자인을 다시 작성해야합니다.

+0

이 내용을 이해할 수는 있지만이를 수행 할 수있는 대안이 있습니까? 동일한 트랜잭션 내에서 새 트랜잭션을 생성합니다. –

+0

트랜잭션 메소드가 다른 빈에 삽입되도록 외부 또는 redactor에서 호출해야합니다. –

+1

AspectJ 기반의 트랜잭션 관리를 로딩 타임이나 컴파일 타임 짜기 및 스프링 애스펙트와 함께 사용할 수있다. 트랜잭션 자체 호출, 개인 트랜잭션 메소드 등을 가질 수있다. 자세한 정보는 Spring 문서를 보라. – Jukka