2011-02-24 3 views
18

@Transactional으로 주석 처리 된 메소드는 이미 트랜잭션이없는 경우 새 트랜잭션을 가져 오지만 트랜잭션 메소드는 트랜잭션을 가져 오지 못한다 트랜잭션이 비 트랜잭션 (non-transactional) 트랜잭션에서 호출 된 경우. 여기에 코드가 있습니다.다른 메소드에서 호출 한 트랜잭션 메소드가 트랜잭션을 얻지 못한다

@Component 
public class FooDao { 
    private EntityManager entityManager; 

    @PersistenceContext 
    protected void setEntityManager(EntityManager entityManager) { 
     this.entityManager = entityManager; 
    } 

    @Transactional 
    public Object save(Object bean) { 
     return this.entityManager.merge(bean); 
    } 

    public Object saveWrap(Object bean) { 
     return save(bean); 
    } 
} 

@Component 
public class FooService { 
    private FooDao fooDao; 

    public void save(Object bean) { 
     this.fooDao.saveWrap(bean); // doesn't work. 
     this.fooDao.save(bean); // works 
    } 
} 

saveWrap() 트랜잭션입니다 save()를 호출하지만 saveWrap()는 변경 사항을 지속하지 않습니다 정기적 방법이다.

저는 Spring 3와 Hibernate 3을 사용하고 있습니다. 여기서 내가 뭘 잘못하고 있니? 감사.

답변

30

이것은 스프링스 AOP의 한계 중 하나입니다. DAO 빈은 실제로 봄에 생성 될 때 프록시이기 때문에 동일한 클래스 내에서 메소드를 호출하면 조언 (트랜잭션)을 호출하지 않는다는 것을 의미합니다. 어떤 다른 포인트 컷에 대해서도 마찬가지입니다.

+2

saveWrap 메소드에 @Transactional 주석을 달아도 아무런 해가 없습니다. 트랜잭션 전파의 기본 동작은 REQUIRED입니다. 즉, 중첩 트랜잭션 (즉, 트랜잭션에 있으며 @Transactional 인 다른 메소드를 호출하는 경우)은 기존 트랜잭션을 사용하고 생성하지 않고 다른 하나는 당신이 무서워하는 경우) –

+0

프록시 cglib를 사용하는 방법에 대해? 나는 모든 클래스에서 cglib 프록시 조언을 기억한다. 심지어 같은 클래스 내에서 호출한다. – hiway

11

예, 예상되는 동작입니다. @Transactional은 스프링에 객체 주위에 프록시를 생성하라고 지시합니다. 프록시는 다른 객체에서 객체에 대한 호출을 가로 챕니다. 프록시는 객체 내의 호출을 인터셉트하지 않습니다.

이 작업을하려면 "outside"에서 호출 한 메서드에 @Transactional을 추가하십시오.

+1

또 다른 옵션은 @Transactional() (가능한 경우 readOnly = true/false, propagation = something 등)을 클래스의 맨 위에 놓은 다음 readOnly 및/또는 전파 전파를 재정의하여 전체 클래스를 트랜잭션으로 표시하는 것입니다. 필요에 따라 메소드 당 값. – esaj

2

이것은 약간 늦었습니다. 그러나이 제한을 극복하기위한 방법을 추가하는 것은 응용 프로그램 컨텍스트에서 스프링 빈을 얻고 메서드를 호출하는 것입니다. 응용 프로그램 컨텍스트에서 스프링 빈을 가져 오면 원래 빈이 아닌 프록시 빈이됩니다. 프록시 빈은 이제 원래 빈 대신에 메소드를 호출하기 때문에 트랜잭션 어드바이스가 그것에 구현 될 것이다.

관련 문제