你知道怎么在事务方法中处理异步方法,保证数据一致性吗?

10 篇文章 0 订阅
2 篇文章 0 订阅

今天同事遇到了,因事务方法中,调用了异步线程,导致数据未查询到(主订单的包装信息,该主订单包含了两个子订单信息)。

解决思路:手动提交事务后,再调用异步线程。

看一下伪代码


@Autowired
@Qualifier(value = "applicationThreadPoolTaskExecutor")
private ThreadPoolTaskExecutor threadPoolTaskExecutor;

@Autowired
private PackageInfoMapper packageInfoMapper;

@Autowired
private OrderMapper orderMapper;

    
@Transactional(rollbackFor = Exception.class)
public void saveOrderPackageInfo(PackageInfo packageInfo){
    //保存包装信息
    packageInfoMapper.save(packageInfo);
    //修改订单状态
    orderMapper.update(packageInfo);
    //异步把包装信息发送至第三方
    threadPoolTaskExecutor.submit(() -> {
      //查询id为1的数据
      List<OrderPackageInfo> 0rderPackageInfo= packageInfoMapper.select(packageInfo.getOrderNo);
      // todo把数据发送发给第三方
    
    });
}

第一种方案:

手动提交事务后,在调用异步线程。

@Autowired
@Qualifier(value = "applicationThreadPoolTaskExecutor")
private ThreadPoolTaskExecutor threadPoolTaskExecutor;

@Autowired
private PackageInfoMapper packageInfoMapper;

@Autowired
private OrderMapper orderMapper;
@Autowired
 private TransactionDefinition transactionDefinition;

    
public void saveOrderPackageInfo(PackageInfo packageInfo){
    TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
    try {
     //保存包装信息
     packageInfoMapper.save(packageInfo);
     //修改订单状态
     orderMapper.update(packageInfo);
   
     platformTransactionManager.commit(transaction);
     System.out.println("提交成功。。。");
       //异步把包装信息发送至第三方
      threadPoolTaskExecutor.submit(() -> {
        //查询id为1的数据
        List<OrderPackageInfo> 0rderPackageInfo= packageInfoMapper.select(packageInfo.getOrderNo);
        // todo把数据发送发给第三方
      
      });
    } catch (Exception e) {
     System.out.println("进入了异常。。。");
     platformTransactionManager.rollback(transaction);
    }
}

第二种方案:

用Spring提供的AbstractPlatformTransactionManager的api

public final void commit(TransactionStatus status) throws TransactionException {
  // ... 省略前面代码
    processCommit(defStatus);

}

  private void processCommit(DefaultTransactionStatus status) throws TransactionException {
  // 事务提交
  // ... 代码省略
// 事务提交后扩展点核心方法      triggerAfterCompletion(status,TransactionSynchronization.STATUS_ROLLED_BACK);

}

private void triggerAfterCompletion(DefaultTransactionStatus status, int completionStatus) {
    if (status.isNewSynchronization()) {
      // 这里可以看到在事务提交后会执行 TransactionSynchronization接口的代码,所以只需要注册一个接口到List<TransactionSynchronization>中
      List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
      TransactionSynchronizationManager.clearSynchronization();
      if (!status.hasTransaction() || status.isNewTransaction()) {
        if (status.isDebug()) {
          logger.trace("Triggering afterCompletion synchronization");
        }
        // No transaction or new transaction for the current scope ->
        // invoke the afterCompletion callbacks immediately
        invokeAfterCompletion(synchronizations, completionStatus);
      }
      else if (!synchronizations.isEmpty()) {
        // Existing transaction that we participate in, controlled outside
        // of the scope of this Spring transaction manager -> try to register
        // an afterCompletion callback with the existing (JTA) transaction.
        registerAfterCompletionWithExistingTransaction(status.getTransaction(), synchronizations);
      }
    }
  }

// TransactionSynchronizationAdapter是TransactionSynchronization的默认实现
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
    @Override
    public void afterCommit() {
        // 事务提交后需要执行的业务逻辑
    }
});

更改后的代码


@Autowired
@Qualifier(value = "applicationThreadPoolTaskExecutor")
private ThreadPoolTaskExecutor threadPoolTaskExecutor;

@Autowired
private PackageInfoMapper packageInfoMapper;

@Autowired
private OrderMapper orderMapper;

    
@Transactional(rollbackFor = Exception.class)
public void saveOrderPackageInfo(PackageInfo packageInfo){
    //保存包装信息
    packageInfoMapper.save(packageInfo);
    //修改订单状态
    orderMapper.update(packageInfo);
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
    @Override
    public void afterCommit() {
        // 事务提交后需要执行的业务逻辑
        //异步把包装信息发送至第三方
      threadPoolTaskExecutor.submit(() -> {
      //查询id为1的数据
      List<OrderPackageInfo> 0rderPackageInfo= packageInfoMapper.select(packageInfo.getOrderNo);
      // todo把数据发送发给第三方
    
    });
    }
  });

    
}

注意:此方法会在事务提交后执行afterCommit 的代码块。

我推荐第二种,代码简化
在这里插入图片描述
PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。点“在看”支持我吧!

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值