当前位置: 首页 > news >正文

spring事务传播级别的实操案例2

一 问题描述

1.1 描述

在一个方法中,先修改数据库,然后使用http请求远程dify服务,出现数据不一致的问题。如下图

2.请求方法后:本地修改数据库成功,dify调用失败;数据库中名称有xx-222改成了xx-333;

怎么办?数据不一致,dify服务没有修改成功,而本地数据库修改成功了,正常要同生共死,一起成功,一起失败的。

二  解决办法

2.1 添加事务级别

1.修改代码后:添加事务传播级别:@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public Result<P> updatePersonalWorkflow(PersonalWorkflowDTO personalWorkflowDto) {// 1. 校验String wkId = personalWorkflowDto.getId();if (StringUtils.isBlank(wkId)) {return ResponseResultUtil.error("工作流id参数有误或为空");}// 2. 获取dir的URLString dirUrl = dirOperationApiUtils.getDirRequestUrl(); // 修改接口dirUrl = dirUrl + "/" + personalWorkflowDto.getId();// 3. 封装请求参数String param = requestDirVisitParam(personalWorkflowDto);// 4. 先操作本地数据库PersonalWorkflowFO personalWorkflowFO = new PersonalWorkflowFO();BeanUtils.copyProperties(personalWorkflowDto, personalWorkflowFO);// 5. 查询一条旧数据PersonalWorkflowFO oldPersonalWorkflowFO = personalWorkflowWrapper.getWorkFlowByWkId(personalWorkflowDto.getId());int flag = 0;try {flag = personalWorkflowWrapper.updatePersonalWorkflow(personalWorkflowFO);if (flag < 1) {return ResponseResultUtil.error("编辑工作流接口,操作本地数据库失败");}String result = IfDdirService.requestDirApiServer(ResultEnum.SUCCESS.getCode(), dirUrl, HttpMethod.POST, "lazy", param);LOGGER.info("调用safe编辑接口,返回结果:{}", result);} catch (Exception e) {// 说明dir调用失败,给本地数据库的修改进行复原String msg = "编辑工作流接口调用编辑接口失败(工作流id:{})";LOGGER.info(msg + "开始恢复本地数据库的数据", oldPersonalWorkflowFO.getId());int rollbackFlag = personalWorkflowWrapper.updatePersonalWorkflow(oldPersonalWorkflowFO);LOGGER.info(msg + "进行恢复本地数据库的数据,操作{}", oldPersonalWorkflowFO.getId(), rollbackFlag < 1 ? "失败,结果小于1" : "成功");throw e;}String info = flag > 0 ? "success" : "failure";return ResponseResultUtil.ok(info);
}

2.2 分析以及问题说明

以上代码的主题逻辑如下:

try {// 数据库操作1:在事务中执行flag = personalWorkflowWrapper.updatePersonalWorkflow(personalWorkflowFO);// 远程调用:如果失败抛出异常String result = IfDdirService.requestDirApiServer(...);} catch (Exception e) {// 手动恢复代码(有问题)int rollbackFlag = personalWorkflowWrapper.updatePersonalWorkflow(oldPersonalWorkflowFO);// 抛出异常:触发Spring事务回滚throw e; // 这里会再次回滚!
}

以上原则上能实现触发本地数据库操作的回滚,但存在如下问题:

当远程调用失败时:

1)数据库更新操作已执行但未提交(事务还在进行中)

2)远程调用抛出异常

3)进入catch块执行手动恢复

4)再次抛出异常,Spring检测到异常,触发事务回滚

5)最终结果:手动恢复的操作也被回滚了!

2.3 优化方案

1.将catch块中自动写的恢复补偿逻辑给去掉,让报异常,执行spring事务管理器所报的异常。

即:移除手动恢复代码,完全依赖Spring事务:

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public Result<P> updatePersonalWorkflow(PersonalWorkflowDTO personalWorkflowDto) {// 1. 校验String wkId = personalWorkflowDto.getId();if (StringUtils.isBlank(wkId)) {return ResponseResultUtil.error("工作流id参数有误或为空");}// 2. 获取dir的URLString dirUrl = dirOperationApiUtils.getDirRequestUrl(); // 修改接口dirUrl = dirUrl + "/" + personalWorkflowDto.getId();// 3. 封装请求参数String param = requestDirVisitParam(personalWorkflowDto);// 4. 先操作本地数据库PersonalWorkflowFO personalWorkflowFO = new PersonalWorkflowFO();BeanUtils.copyProperties(personalWorkflowDto, personalWorkflowFO);int flag = 0;try {flag = personalWorkflowWrapper.updatePersonalWorkflow(personalWorkflowFO);if (flag < 1) {return ResponseResultUtil.error("编辑工作流接口,操作本地数据库失败");}String result = IfDdirService.requestDirApiServer(ResultEnum.SUCCESS.getCode(), dirUrl, HttpMethod.POST, "lazy", param);LOGGER.info("调用safe编辑接口,返回结果:{}", result);} catch (Exception e) {// 说明dir调用失败,给本地数据库的修改进行复原String msg = "编辑工作流接口调用编辑接口失败(工作流id:{})";LOGGER.info(msg + "开始恢复本地数据库的数据", oldPersonalWorkflowFO.getId());throw e;}String info = flag > 0 ? "success" : "failure";return ResponseResultUtil.ok(info);
}

2.4 结论

  • ✅ REQUIRED传播级别下,远程调用失败会触发事务回滚

  • ❌ 不需要手动在catch块中恢复数据

  • ✅ Spring会在方法抛出异常时自动回滚整个事务

  • ❌ 手动恢复+抛出异常会导致重复回滚,逻辑混乱

结论:完全信任Spring的事务管理机制,移除手动恢复代码即可。

当一个方法使用事务传播级别required,先执行本地数据库操作,然后调用dify服务,当dify远程调用失败时,会执行本地事务回滚。

原因是 触发异常,spring事务管理器捕捉到异常,执行本地数据库回滚,说白了就是dify失败报异常,捕捉到能触发本地数据库操作回滚。即当dify远程调用失败时,会执行本地事务回滚。

https://chat.deepseek.com/a/chat/s/56b88c28-b88c-4b55-ae6b-509539e3c257

http://www.dtcms.com/a/419304.html

相关文章:

  • 泰州专一做淘宝网站如何用html做网站头像
  • 电子商务网站设计与实现个人网站做捐赠发布违法吗
  • Java滑动窗口算法题目练习
  • 介绍一下HTTP和WebSocket的头部信息
  • Linux系统学习之---库的理解和加载(毛坯初版...)
  • 南山模板网站建设公司怎么看网站的外链
  • 企业网站策划大纲模板文山住房和城乡建设局网站
  • Linux 基础IO与系统IO
  • 【IEDA】已解决:IDEA中jdk的版本切换
  • idea推荐springboot+mybatis+分页查询插件之PageHelper
  • 南非网站域名做网站微信支付多少钱
  • 网站开发 图形验证码网站建设衤金手指下拉10
  • OPenssh6代码移植的依赖库 OpenSSL双库连接问题的解决方案
  • 商务网站建设组成包括网站优化wordpress 换行
  • tiktok scheme
  • Xrdp 远程桌面配置【笔记】
  • 【Linux】倒计时和进度条实现
  • 网站建设需要用到哪些软件有哪些系统安装wordpress
  • 梯度下降(Gradient Descent)
  • 东莞市建设规划局网站游戏类企业网站模板
  • C++---bind(绑定函数或函数对象的参数)
  • 网站和域名网站开发技术是什么
  • 个人如何开网站西安网络推广外包公司
  • 国产处理器飞腾CPU各系列综合性能对比
  • 南宁网站设计推广wordpress+授权登录
  • 网站建设深圳哪里学品牌建设提升
  • 《LangChain入门指南》学习笔记1:第1章 LangChain:开启大语言模型时代的钥匙
  • 国清汇携手社保基金会推出《国脉相承·传世养老基金》
  • 3、内存系统详解 - 从DDR演进到GPU内存架构的认知基石
  • 芯片和半导体:Intel开始布局14A工艺