Spring: @Transactional(propagation=Propagation.SUPPORTS)方法与无@Transactional方法的区别

8
@Transactional(propagation = Propagation.SUPPORTS)和没有@Transactional注解有什么区别?
@Transactional(propagation = Propagation.SUPPORTS)
public void MyMethod()

vs

public void MyMethod()

如果已经存在一个事务,那么没有注释的代码也会使用该事务,否则就不使用事务并继续执行。
3个回答

3

有一点小的不同。假设我们有两个方法a()b(),并且a()将调用b()a本身是事务性的,其传播级别为Propagation.REQUIRED,但是b有一次被注释为@Transactional(propagation = Propagation.SUPPORTS),另一次则没有注释。

情况1:

  @Transactional
  public void a() {
    for (int i = 0; i < 10; i++) {
      try {
        productRepository.b(i, "product " + i);
      } catch (RuntimeException ex){
        // do nothing
      }
    }
  }


  public void b(int id, String name) {
    if(id > 5)
      throw new RuntimeException();
    String sql = "INSERT INTO test_table VALUES(?, ?)";
    template.update(sql, id, name);
  }

如果情况1中我们有aspect() -> a() -> b(),并且您能够防止RuntimeException到达aspect,并且方面检查事务以查看其是否标记为回滚,因此方面认为此事务成功,并且您可以在我们的数据库中看到此结果。

0,product 0
1,product 1
2,product 2
3,product 3
4,product 4
5,product 5

虽然抛出了多个异常,但我们仍能提交已完成的操作。
现在考虑第二种情况:
  @Transactional
  public void a() {
    for (int i = 0; i < 10; i++) {
      try {
        productRepository.b(i, "product " + i);
      } catch (RuntimeException ex){
        // do nothing
      }
    }
  }

  @Transactional(propagation = Propagation.SUPPORTS)
  public void b(int id, String name) {
    if(id > 5)
      throw new RuntimeException();
    String sql = "INSERT INTO test_table VALUES(?, ?)";
    template.update(sql, id, name);
  }

propagation = Propagation.SUPPORTS 时,如果存在一个事务,它将使用该事务。因此,如果你在 b 中抛出异常,则会将同一事务标记为回滚,即使你使用 try/catch 块防止 RuntimeExceptiona() 中触发 aspect ,事务已经被标记为在 b 中回滚,因此在数据库中看不到结果。 aspect() -> a() -> aspect() -> b()

感谢 Laurentiu Spilca,参见此视频并阅读评论部分。


1

从您的链接中可以看出,Propagation.SUPPORTS 对同步可能会产生影响:

SUPPORTS 稍微与没有事务不同,因为它定义了一个事务范围,同步将适用于该范围。因此,相同的资源(JDBC 连接、Hibernate 会话等)将在整个指定范围内共享。


我还是不明白,如果从另一个带有 @Transactional 注解的方法(我们称其为 parentMethod)调用 myMethod,它会使用由 parentMethod 创建的事务,是吗? - Olivier Boissé
@OlivierBoissé 是的,但它还会在数据库资源上添加额外的同步。 - user7294900
我的意思是,如果myMethod没有注解@Transactional,它会使用由parentMethod创建的事务吗? - Olivier Boissé
@OlivierBoissé 是的,在 @Transactional 内部调用的所有方法都是事务的一部分(父事务)。 - user7294900
3
我仍然看不到在myMethod周围使用Propagation.SUPPORTS的好处,你所说的附加数据库资源同步是什么意思? - Olivier Boissé
Olivier,我和你一样并不认为有什么区别。总的来说,这似乎是一个非常特定于实现的角落案例。 - Martin Andersson

-1

是的,如果没有任何注释,它将使用现有的事务,但如果没有任何事务,您不想在事务失败时撤消更改吗。

传播还具有其他属性,如果您的方法不依赖于父事务并且在单独的事务范围内运行,可能可以选择REQUIRES_NEW,这样您就可以为自己的方法拥有独立的事务。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接