【问题标题】:@Transactional method calling another method without @Transactional anotation?@Transactional 方法调用另一个没有@Transactional 注释的方法?
【发布时间】:2011-09-07 12:47:48
【问题描述】:

我在 Service 类中看到了一个方法,该方法被标记为 @Transactional,但它还调用了同一类中未标记为 @Transactional 的一些其他方法。

这是否意味着对单独方法的调用导致应用程序打开到 DB 的单独连接或暂停父事务等?

一个没有任何注解的方法被另一个带有@Transactional注解的方法调用的默认行为是什么?

【问题讨论】:

    标签: java spring spring-transactions transactional


    【解决方案1】:

    当您在事务块中调用没有@Transactional 的方法时,父事务将继续使用新方法。它将使用来自父方法的相同连接(带有@Transactional),并且在被调用方法中引起的任何异常(不带有@Transactional)都会导致事务按照事务定义中的配置回滚。

    如果您在同一实例中从带有@Transactional 的方法调用带有@Transactional 注释的方法,则被调用的方法的事务行为不会对事务产生任何影响。但是如果你从另一个具有事务定义的方法调用具有事务定义的方法,并且它们在不同的实例中,那么被调用方法中的代码将遵循被调用方法中给出的事务定义。

    您可以在spring transaction documentation声明性事务管理部分找到更多详细信息。

    Spring 声明式事务模型使用 AOP 代理。所以 AOP 代理负责创建事务。仅当实例中的方法从实例外部调用时,AOP 代理才会处于活动状态。

    【讨论】:

    • 这是弹簧默认行为吗?
    • 是的。这是默认行为。
    • @Tomasz 是的。但还应该提到的是,更改从另一个 @Transactional 方法调用的方法上的事务传播将没有效果。
    • @Tomasz,这就是我所说的will follow the transaction definitions given in the called method 的意思。但是如果调用来自同一个对象实例,则不会产生任何影响,因为调用不会通过负责事务维护的 aop 代理传播。
    • @Filip,这并不完全正确,如果您从不同的对象/实例调用具有 @Transactional 定义的方法,那么即使调用方法具有不同的 @Transactional 属性,被调用的方法将遵循它自己的事务定义。
    【解决方案2】:
    • 这是否意味着对单独方法的调用导致应用程序打开到 DB 的单独连接或暂停父事务等?

    这取决于propagation level。这里是所有可能的级别values

    例如,如果传播级别为 NESTED,当前事务将“暂停”并创建一个新事务(注意:嵌套事务的实际创建仅适用于特定事务管理器 )

    • 一个没有任何注解的方法被另一个带有@Transactional注解的方法调用的默认行为是什么?

    默认传播级别(您称之为“行为”)是REQUIRED。如果调用带有 @Transactional 注释的“内部”方法(或通过 XML 以声明方式进行事务处理),它将在 same transaction 中执行,例如“没有什么新东西”被创建。

    【讨论】:

    • NOT_SUPPORTED 的子调用没有任何注释呢?它是继承 NOT_Supported 还是他们打开了一个新事务,因为 REQUERED 是默认设置?例如: f1.call(){ f2() } 带有注释 NOT_SUPPORTED 用于 f1 和 non 用于 f2。
    【解决方案3】:

    @Transactional 标记事务边界(开始/结束),但事务本身绑定到线程。一旦事务开始,它就会在方法调用之间传播,直到原始方法返回并且事务提交/回滚。

    如果调用具有@Transactional 注释的另一个方法,则传播取决于该注释的传播属性。

    【讨论】:

    • 这3个答案在某种程度上相互冲突,不确定哪个更准确。
    • @EricWang 只是想分享一下我今天测试了这个场景,Arun P Johny (with cmets) 的答案对于 的这个场景是最准确的内部调用。
    【解决方案4】:

    如果内部方法没有使用@Transactional注解,内部方法会影响外部方法。

    如果内部方法也用@Transactional 和REQUIRES_NEW 注释,则会发生以下情况。

    ...
    @Autowired
    private TestDAO testDAO;
    
    @Autowired
    private SomeBean someBean;
    
    @Override
    @Transactional(propagation=Propagation.REQUIRED)
    public void outerMethod(User user) {
      testDAO.insertUser(user);
      try{
        someBean.innerMethod();
      } catch(RuntimeException e){
        // handle exception
      }
    }
    
    
    @Override
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void innerMethod() {
      throw new RuntimeException("Rollback this transaction!");
    }
    

    内部方法使用REQUIRES_NEW 进行注释并抛出一个RuntimeException,因此它将其事务设置为回滚,但不会影响外部事务。外部事务在内部事务开始时暂停,然后在内部事务结束后恢复。它们彼此独立运行,因此外部事务可以成功提交。

    【讨论】:

    • 为了澄清初学者,我很确定 innerMethod() 需要位于与 outerMethod() 不同的 bean(也称为 Spring 管理的 java 对象)上。如果它们都在同一个bean上,我认为innerMethod实际上不会使用在其注释中声明的事务行为。相反,它将使用在 outerMethod() 声明中声明的内容。这是因为 Spring 处理 AOP 的方式,它用于 @Transactional 注释 (docs.spring.io/spring/docs/3.0.x/spring-framework-reference/…)
    猜你喜欢
    • 2018-02-23
    • 2021-01-01
    • 2020-03-29
    • 2015-05-27
    • 1970-01-01
    • 2011-07-03
    • 2012-08-25
    • 2019-11-18
    • 2021-04-25
    相关资源
    最近更新 更多