ChatGPT解决这个技术问题 Extra ChatGPT

@Transactional 方法调用另一个没有@Transactional 注释的方法?

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

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

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


4
4javier

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

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

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

Spring 声明式事务模型使用 AOP 代理,因此 AOP 代理负责事务的创建。只有当被调用的方法属于与调用者不同的 Spring Bean 时,AOP 代理才会处于活动状态。


这是春天的默认行为吗?
@Tomasz 是的。但还应该提到的是,更改从另一个 @Transactional 方法调用的方法上的事务传播将无效。
@Tomasz,这就是我所说的 will follow the transaction definitions given in the called method 的意思。但是如果调用来自同一个对象实例,它不会产生任何影响,因为调用不会通过负责事务维护的 aop 代理传播。
@Filip,这不完全正确,如果您从不同的对象/实例调用具有 @Transactional 定义的方法,那么即使调用方法具有不同的 @Transactional 属性,被调用的方法也将遵循它自己的事务定义.
@ArunPJohny 这是什么意思:“在同一个实例中”?例如。我有带有事务注释的父方法,在这个方法中我从另一个服务调用另一个带有事务的方法......当在子方法中出现异常时,我想回滚所有内容......
t
tolitius

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

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

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

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

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


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

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

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


3个答案在某种程度上相互冲突,不确定哪个更准确。
@EricWang 只是想分享一下我今天测试了这个场景,Arun P Johny (带评论) 的答案对于这种 internal 调用场景是最准确的。
C
C-Otto

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

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

...
@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/…)