Spring Data:重试时回滚事务

Posted

技术标签:

【中文标题】Spring Data:重试时回滚事务【英文标题】:Spring Data: rollback transaction on retry 【发布时间】: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 时保存。

【问题讨论】:

【参考方案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

【讨论】:

以上是关于Spring Data:重试时回滚事务的主要内容,如果未能解决你的问题,请参考以下文章

Spring Kafka - 事务回滚后重试时,通过侦听器容器事务发布消息和提交记录偏移失败

使用JPA的Spring数据不会在出错时回滚事务

坦言spring中事务重试异步执行注解

typescript 重试时重试逻辑

JPA 事务回滚重试和恢复:将实体与自动递增的@Version 合并

Polly 在重试时更改查询字符串