【问题标题】:Spring : Difference between method with @Transactional(propagation=Propagation.SUPPORTS) vs no @TransactionalSpring:使用@Transactional(propagation=Propagation.SUPPORTS) 的方法与没有@Transactional 的方法之间的区别
【发布时间】:2020-01-23 03:06:29
【问题描述】:

带有@Transactional(propagation = Propagation.SUPPORTS) 的方法与完全没有@Transactional 注释的方法有什么区别?

@Transactional(propagation = Propagation.SUPPORTS)
public void MyMethod()

public void MyMethod()

如果一个已经打开,没有注解的不也使用一个事务,否则继续没有任何事务?

【问题讨论】:

    标签: spring transactions spring-transactions


    【解决方案1】:

    有一点不同。假设我们有两个方法a()b(),而a() 将调用b()a本身是跨国的,它的传播等级是Propagation.REQUIRED,但是b有一次被@Transactional(propagation = Propagation.SUPPORTS)注解,一次没有被注解。

    案例一:

      @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() -&gt; a() -&gt; b() 并且您可以阻止 RuntimeException 到达方面,方面检查事务以查看它是否标记为回滚,因此方面认为此事务成功,您可以看到我们有这个结果在我们的数据库中

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

    即使抛出了多个异常,但我们能够提交到目前为止已经完成的操作。

    现在考虑案例 2:

      @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 块来阻止 RuntimeException 到达 a() 中的方面,事务已经被标记为回滚在b 中,您在数据库中看不到任何结果。 aspect() -&gt; a() -&gt; aspect() -&gt; b()

    感谢 Laurentiu Spilca,请参阅 this 并阅读评论部分

    【讨论】:

      【解决方案2】:

      从您的链接中,它指出Propagation.SUPPORTS 可能会影响 同步:

      SUPPORTS 与完全无事务略有不同,因为它定义了同步将适用的事务范围。因此,相同的资源(JDBC 连接、Hibernate Session 等)将在整个指定范围内共享

      【讨论】:

      • 我还是不明白,如果myMethod被另一个@Transactional方法调用(我们称之为parentMethod),它会使用parentMethod创建的事务不是吗?跨度>
      • @OlivierBoissé 是的,但它还增加了对数据库资源的额外同步
      • 我的意思是如果myMethod没有注解@Transactional,是否使用parentMethod创建的事务?
      • @OlivierBoissé 是的,您在@Transactional 中调用的所有方法都是(父)事务的一部分
      • 所以我仍然看不到在myMethod 周围使用Propagation.SUPPORTS 的好处,您所说的对数据库资源的额外同步是什么意思?
      【解决方案3】:

      是的,如果一个已经打开,没有任何注释的将使用现有事务,但如果没有任何注释,如果您的事务失败,您不想恢复更改。

      如果您的方法不依赖于父事务并在单个事务范围内运行,传播还有其他属性很好,也许您可​​以选择REQUIRES_NEW 这样您的方法可以有独立的事务。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-13
        • 2012-07-21
        • 2011-09-07
        • 2015-02-23
        • 2019-07-12
        • 2018-02-26
        • 2011-02-21
        • 2020-06-12
        相关资源
        最近更新 更多