繁体   English   中英

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

[英]Indirect Hibernate/JPA method call loses transaction

我正在使用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()只在被调用时间接地松散了事务?

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

在代理模式(默认设置)下,只拦截通过代理进入的外部方法调用。 这意味着实际上,自调用目标对象中的一个方法调用目标对象的另一个方法,即使被调用的方法用@Transactional标记,也不会在运行时导致实际的事务。

如果您希望自我调用也包含在事务中,请考虑使用AspectJ模式(请参阅下表中的mode属性)。 在这种情况下,首先不会有代理; 相反,目标类将被编织(即,它的字节代码将被修改),以便在任何类型的方法上将@Transactional转换为运行时行为。

@Autowired引用B b (在A类中)包含一个Spring AOP事务感知代理。

b.inner() ,您在事务感知实例上调用它,并将其标记为@Transactional 因此,启动了Spring托管事务。

b.outer() ,它也在事务感知实例上,但它不是 @Transactional 因此,Spring管理的事务启动。

一旦你进入outer()的调用,对inner() outer()的调用就不会通过事务感知代理,而是直接调用它。 它与this.inner()相同。 由于您是直接调用它,而不是通过代理调用它,因此它没有Spring事务感知语义。

由于没有启动任何事务,因此会导致TransactionRequiredException

可能的解决方案包括使方法outer() @Transactional

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

或者制作整个班级@Transactional

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

事务上下文持续超过spring bean整个生命周期的范围。 @Transactional表示法具有整个组件的范围,您应该将@Component注释为@Transactional,例如

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

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

内部和外部的方法应该完成单独的工作单元。 如果你需要一些辅助函数或者你有什么好处,但是需要事务边界的工作单元应该作用于每个方法。 请参阅@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