Spring Boot 应用中的事务管理与 Feign 调用问题分析及解决

问题描述

在SpringBoot微服务的项目中,在方法一进行的途中,向数据库插入了一条数据,并得到了这条数据的id,然后远程调用另外一个服务的方法。在另外一个服务的方法中使用这个id查询数据库中的这条数据,查询出来的值总是空值。

在微服务架构下,遇到这样的场景:一个服务需要调用另一个服务的接口来进行一系列操作,而这些操作又需要保证事务的一致性。然而,在实际开发过程中,可能会遇到一些问题,比如事务中所做的更改无法被 Feign 调用所看到。

问题分析

这个问题的根本原因在于事务隔离级别和 Feign 调用之间的交互。当在一个事务中执行了一系列操作后,这些操作所产生的数据更改只有在事务提交之后才会对外可见。而在同一事务中,Feign 调用实际上是在一个新的上下文中执行的,这意味着它不会看到未提交的更改。

可能的原因

  • 事务隔离级别默认情况下,Spring 的事务隔离级别是 ISOLATION_DEFAULT,这意味着它会使用底层数据库的默认隔离级别。如果数据库默认隔离级别是 READ_COMMITTED 或 REPEATABLE_READ,那么在事务中更新的数据在当前事务提交之前对其他事务不可见。
  • Feign 调用与事务:Feign 调用实际上是在当前事务之外发生的,这意味着它不会受到当前事务的影响。因此,如果您在事务中更新了数据,Feign 调用将不会看到这些未提交的更改。

解决方案

方案一:提交事务后再调用 Feign

确保在调用 Feign 服务之前先提交事务。这可以通过将 Feign 调用放在事务范围之外来实现。例如:

@Override
public void insertA() {
    // ... (之前的代码)

    //添加

    // 提交事务
    PlatformTransactionManager transactionManager = TransactionAspectSupport.currentTransactionManager();
    TransactionDefinition def = new DefaultTransactionDefinition();
    TransactionStatus status = transactionManager.getTransaction(def);
    transactionManager.commit(status);

    // 远程调用
    //...(后面的代码)

}

方案二:使用 PROPAGATION_REQUIRES_NEW

如果希望在同一个方法中保持事务的原子性,但又需要确保 Feign 调用能够看到最新的数据,可以使用 PROPAGATION_REQUIRES_NEW 传播行为。这将创建一个新的事务,即使在当前事务中也是如此。

@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)

方案三:使用 @Async 异步调用

如果另外的操作不是必须同步完成的,可以考虑使用异步调用来避免阻塞事务。

// TODO tcc、可靠消息一致性、最大努力通知

点赞

当前页面评论已关闭。

隐藏
变装