2016-06-23 1 views
1

@TransactionalEventListener를 사용하여 이벤트를 수신하려고하는데 전체 트랜잭션이 끝나기도 전에 이벤트가 수신됩니다. 메서드가 예외를 throw해도 이벤트는 수신 대기합니다. 내 청취자가 삽입 내 거래 방법 완료되는 즉시 여기 Spring @TransactionalEventListener가 예상대로 작동하지 않습니다.

내가이 시나리오에서는

@Component 
public class SampleListener{ 

    @TransactionalEventListener 
    public void handleSomeTransactionalEvent(SampleEvent event){ 
     //Some Logic 
    } 
} 

@Service 
@Transactional 
public class SampleInsertService{ 

    @Autowired 
    private ApplicationEventPublisher applicationEventPublisher; 

    public void someTransactionalMethod(SomeDTO someDTO){ 
      //Delete all call 

      //Again Insert all calls 

      //Publish event after insert 
      applicationEventPublisher.publishEvent(new SampleEvent(this, String.EventType, someDTO)); 

      /** Some other call to DB which throws exception **/ 
    } 

} 


public class SampleEvent implements ApplicationEvent{ 

    private String eventType; 

    public SampleEvent(Object source, String eventType, SampleDTO sampleDTO){ 
      //some logic 
    } 

} 

을하려고하고있는 무슨의 샘플 코드를 호출지고 있습니다. 나는 모든 DB 호출이 끝나고 커밋이 완료된 후에 이것이 호출되어야한다고 생각한다. 나는 뭔가를 놓친다. 나는 Spring 4.3.0을 사용하고있다. 제발 날 안내 해줘.

답변

1

문제점을 파악했습니다. Spring MVC를 사용하지 않는다면이 문제는 발생하지 않을 것이다. 이 문제는 rootapplicationcontext와 child webapplicationcontext (스프링 MVC 용) 모두에로드 된 리스너 클래스로 인해 발생했습니다.

내 application-context.xml과 spring-web.xml에서 일반 구성 요소 검사를 수행했습니다. 따라서 리스너 클래스가 두 번로드됩니다. application-context.xml에 대해 한 번, spring-web.xml에 대해 다시 한 번. spring-web.xml의 일반 구성 요소 검색을 제거하고 spring-web.xml에서 컨트롤러 패키지 및 필터 패키지 만 언급하면 ​​문제가 해결되었습니다.

트랜잭션 이벤트 수신기는 트랜잭션 커밋 후에 한 번만 호출되었습니다.

+0

로드되는 XML 구성 파일이 하나뿐입니다. 그러나, 나는 당신과 같은 증상을보고 있습니다. 내 구성 요소가 두 번로드되는지 확인하는 가장 좋은 방법은 무엇입니까? –

+0

@DavidWebb, listerner 클래스가 나와 설명 된 시나리오와 같이 두 번로드 될 수 있다고 생각되면 애플리케이션 시작시 Spring에 의해 생성 된 로그에서 확인할 수 있어야합니다. 스프링 빈 초기화에 대한 정보를 얻으려면 TRACE 레벨을 켜야한다고 생각합니다. 시작할 때 로그에서 두 번 발견하면 문제 일 수 있습니다. 희망이 도움이됩니다. – tejaswini

1

TransactionalEventListener는 다른 TransactionPhase에서 수신 대기 할 수 있습니다. 어노테이션에서 다른 단계를 지정할 수 있습니다. 귀하의 경우 AFTER_COMMIT 또는 AFTER_COMPLETION이 유용 할 수 있습니다.

+0

@TransactionalEventListener의 기본 단계가 AFTER_COMMIT이므로이 단계를 언급하지 않았습니다. 나는 handleSomeTransactionalEvent()가 모든 DB 호출이 Service 메소드에서 종료 된 후에 호출되어야한다고 생각한다. 그러나 그것은 사실이 아닙니다. 마지막 DB 호출이 실행되기 전에 호출되고 DB에 커밋되기 전에 호출됩니다. 제가 뭔가를 놓치고 있다면 알려주실 수 있습니까? – tejaswini