简体   繁体   English

间接Hibernate / JPA方法调用丢失事务

[英]Indirect Hibernate/JPA method call loses transaction

I'm using Spring/JPA2/hibernate with this code: 我正在使用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(); }
}

Why does inner() only when called indirectly loose the transaction? 为什么inner()只在被调用时间接地松散了事务?

http://static.springsource.org/spring/docs/current/reference/transaction.html#transaction-declarative-annotations http://static.springsource.org/spring/docs/current/reference/transaction.html#transaction-declarative-annotations

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. 这意味着实际上,自调用目标对象中的一个方法调用目标对象的另一个方法,即使被调用的方法用@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. 如果您希望自我调用也包含在事务中,请考虑使用AspectJ模式(请参阅下表中的mode属性)。 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. 相反,目标类将被编织(即,它的字节代码将被修改),以便在任何类型的方法上将@Transactional转换为运行时行为。

The @Autowired reference B b (inside class A ), is wrapped with a Spring AOP transaction-aware proxy. @Autowired引用B b (在A类中)包含一个Spring AOP事务感知代理。

When b.inner() is called, you are invoking it on the transaction-aware instance, and it is marked as @Transactional . b.inner() ,您在事务感知实例上调用它,并将其标记为@Transactional Thus a Spring managed transaction is started. 因此,启动了Spring托管事务。

When b.outer() is called, it is also on a transaction-aware instance, but it is not @Transactional . b.outer() ,它也在事务感知实例上,但它不是 @Transactional Thus a Spring managed transaction is not started. 因此,Spring管理的事务启动。

Once you are inside the invocation of outer() the call to inner() is not going through the transaction-aware proxy, it is being invoked directly. 一旦你进入outer()的调用,对inner() outer()的调用就不会通过事务感知代理,而是直接调用它。 It is the same as this.inner() . 它与this.inner()相同。 Since you are invoking it directly, and not through the proxy, it does not have the Spring transaction-aware semantics. 由于您是直接调用它,而不是通过代理调用它,因此它没有Spring事务感知语义。

Since no transaction has been started, this results in the TransactionRequiredException . 由于没有启动任何事务,因此会导致TransactionRequiredException

Possible solutions include making the method outer() @Transactional . 可能的解决方案包括使方法outer() @Transactional

   @Transactional
   public void outer() { inner(); }

Or making the entire class @Transactional . 或者制作整个班级@Transactional

@Transactional   
@Component
class B {
   @PersistenceContext
   EntityManager em;

The transactional context lasts over the scope of your spring bean's entire lifespan. 事务上下文持续超过spring bean整个生命周期的范围。 @Transactional notation has a scope of the entire component and you should annotate your @Component as @Transactional eg @Transactional表示法具有整个组件的范围,您应该将@Component注释为@Transactional,例如

@Transactional
@Component
class B {
    @PersistenceContext 
    EntityManager em;

    public inner() { }
    public outer() { }
}

The methods inner and outer should accomplish individual units of work. 内部和外部的方法应该完成单独的工作单元。 If you need some helper function or what have you that is fine, but the unit of work that requires the transactional boundary should be scoped to each method. 如果你需要一些辅助函数或者你有什么好处,但是需要事务边界的工作单元应该作用于每个方法。 See the spring docs on @Transactional http://static.springsource.org/spring/docs/3.0.x/reference/transaction.html 请参阅@Transactional上的spring文档http://static.springsource.org/spring/docs/3.0.x/reference/transaction.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM