【问题标题】:Spring Data: rollback transaction on retrySpring Data:重试时回滚事务
【发布时间】:2018-05-24 10:09:09
【问题描述】:

有一个实体:

@Entity
class A {
    ...
    @Version
    int version; 
}

A 实例更新以乐观的方式实现:

@Transactional(rollbackFor = {StaleStateException.class})
@Retryable(value = {StaleStateException.class})
public void updateA() {
    A a = findA();
    B b = new B();
    // Update "a" somehow
    a.update();
    // "b" is saved on each retry!
    save(b);
}

如 cmets 中所述,似乎在发生StaleStateException 时事务没有回滚,因此每次重试时都会保存B 实例。

是否可以在重试时回滚事务?

所需的行为是 b 仅在成功更新 a 时保存。

【问题讨论】:

    标签: java hibernate spring-boot spring-data optimistic-locking


    【解决方案1】:

    我认为这可能与@Retryable 配置有关。

    正如文档所说 https://docs.spring.io/spring-batch/trunk/reference/html/retry.html#statelessRetry 无状态重试只不过是一个循环,不断调用相同的方法直到它成功。

    问题是每次它失败时调用的第一个拦截器是不会重新抛出异常的可重试的,所以它永远不会到达@Transactional

    所以发生的情况是,每次重试都将遵循默认事务传播,该传播将在上下文中重用具有new B() 的相同打开事务。

    您可以通过调试检查我是否处于正确的领先地位:如果您输入第二次重试并发现A 在更新块之前已经更新,那么我应该是正确的。

    您可以通过两种方式修复:

    要么分两块(先用嵌套事务重试)

    @Retryable(value = {StaleStateException.class})
    public void retryableUpdate() {
       updateA();
    }
    
    @Transactional(rollbackFor = {StaleStateException.class})
    public void updateA() {
        A a = findA();
        B b = new B();
        // Update "a" somehow
        a.update();
        // "b" is saved on each retry!
        save(b);
    }
    

    让事务先回滚。

    或者您可以按照文档并使用有状态重试https://docs.spring.io/spring-batch/trunk/reference/html/retry.html#statefulRetry

    【讨论】:

      猜你喜欢
      • 2018-08-07
      • 1970-01-01
      • 2020-08-06
      • 2014-12-11
      • 2011-10-04
      • 1970-01-01
      • 1970-01-01
      • 2018-05-23
      • 1970-01-01
      相关资源
      最近更新 更多