@Transactional 方法调用另一个没有@Transactional 注释的方法?
Posted
技术标签:
【中文标题】@Transactional 方法调用另一个没有@Transactional 注释的方法?【英文标题】:@Transactional method calling another method without @Transactional anotation? 【发布时间】:2011-09-07 12:47:48 【问题描述】:我在 Service 类中看到了一个方法,该方法被标记为 @Transactional
,但它还调用了同一类中未标记为 @Transactional
的一些其他方法。
这是否意味着对单独方法的调用导致应用程序打开到 DB 的单独连接或暂停父事务等?
一个没有任何注解的方法被另一个带有@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/…)以上是关于@Transactional 方法调用另一个没有@Transactional 注释的方法?的主要内容,如果未能解决你的问题,请参考以下文章