我在这段代码中使用 Spring/JPA2/hibernate:
class A {
@Autowired
B b;
@RequestMapping("/test")
public void test(final HttpServletRequest r1, HttpServletResponse r2) throws ... {
b.inner(); // Works
b.outer(); // javax.persistence.TransactionRequiredException:
// no transaction is in progress ... :|
}
@Component
class B {
@PersistenceContext
EntityManager em;
public void outer() { inner(); }
@Transactional
public void inner() { em.flush(); }
}
为什么 inner()
只有在间接调用时才会松动事务?
最佳答案
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.
Consider the use of AspectJ mode (see mode attribute in table below) if you expect self-invocations to be wrapped with transactions as well. In this case, there will not be a proxy in the first place; instead, the target class will be weaved (that is, its byte code will be modified) in order to turn @Transactional into runtime behavior on any kind of method.
@Autowired
引用 B b
(在类 A
内),用 Spring AOP 事务感知代理包装。
当 b.inner()
被调用时,您是在事务感知实例上调用它,它被标记为 @Transactional
。因此启动了 Spring 管理的事务。
当 b.outer()
被调用时,它也是在事务感知实例上,但它不是 @Transactional
。因此,Spring 管理的事务未启动。
一旦您进入 outer()
的调用,对 inner()
的调用不会通过事务感知代理,它被直接调用。它与 this.inner()
相同。由于您是直接调用它,而不是通过代理调用它,因此它不具有 Spring 事务感知语义。
由于尚未启动任何事务,这将导致 TransactionRequiredException
。
可能的解决方案包括使方法 outer()
@Transactional
。
@Transactional
public void outer() { inner(); }
或者使整个类成为@Transactional
。
@Transactional
@Component
class B {
@PersistenceContext
EntityManager em;
关于java - 间接 Hibernate/JPA 方法调用丢失事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6499618/