Spring @Transactional 展示位置

Spring @Transactional placement

我最近在玩 Spring/JPA2 以更好地了解它的工作原理。在我的实验中,我发现了一些奇怪的行为。问题是:

为什么下面的代码运行良好(在db中添加确认记录):

@Repository
public class UserDAO {

    @PersistenceContext
    EntityManager em;

    @Transactional
    public void add(User user) {
        doAdd(user);
    }

    public void doAdd(User user) {
        em.persist(user);
    }
}

但是下面的(@Transactional注解移到了内部方法):

@Repository
public class UserDAO {

    @PersistenceContext
    EntityManager em;

    public void add(User user) {
        doAdd(user);
    }

    @Transactional
    public void doAdd(User user) {
        em.persist(user);
    }
}

抛出异常:

javax.persistence.TransactionRequiredException: No transactional EntityManager available
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:273)
    at com.sun.proxy.$Proxy556.persist(Unknown Source)
    at com.example.UserDAO.doAdd(UserDAO.java:24)
    ...

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional.

Source

@Transactional 注释支持通过将实际的 DAO 实例包装在代理中来工作,代理会拦截方法调用和 starts/commits 事务。在第二个示例中,实际的 UserDAO 实例正在调用 doSave 方法,因此没有代理来拦截方法调用。