-
优雅实现多系统一致性补偿方案(多系统协同)
- 网站名称:优雅实现多系统一致性补偿方案(多系统协同)
- 网站分类:技术文章
- 收录时间:2025-08-03 01:42
- 网站地址:
“优雅实现多系统一致性补偿方案(多系统协同)” 网站介绍
前言
我们在开发的过程中,如果一个业务操作需要本地写MYSQL数据以及对第三方系统做写操作,那么这种流程就涉及到分布式系统一致性的问题,然而并非所有系统都能使用成熟的分布式事务方案
案例说明
以一个财务报账业务为例,涉及到的系统如下:
详细解释下各系统作用:
“审核通过”业务流程
当审核人员审核通过时,大致流程如下:
代码如下
风险分析
如图所示,如果在1和2出现异常,由于有事务的存在,操作1内的几条mysql写操作会被回滚,因此所有数据都没有任何变化。
但如果1和2正常执行,操作3发生异常,操作1的数据会因为事务回滚,但操作2并不能。因此整个系统会出现一个很诡异的现象:单据系统内,没有任何日志记录,用户操作的数据也没有保留下来,但BPM那边却已经审核通过了,这在任何正常流程中,都是不可能出现的状态。
对于用户而言,他在页面会收到报错,然后可能会再次点击“审核通过”,而此时BPM那边却显示,流程已经走到下一个节点,该用户无权限操作。
问题分析
根本原因其实不难,因为MYSQL事务只能管他自己,没法控制第三方系统
解决思路
一个字:拆!
对于分布式系统,没有任何人能保证远程调用不出问题,因此在做设计时,就必须能够对这种情况做出应对
上面的操作,打包放进一个大事务就是根因,因此方案就是将大事务拆开,在拆分时,需要遵循以下几个原则:
整体思路就是这样
基于以上原则,改动如下
第一步,新建一张任务表:
CREATETABLE`transaction_job` (
`id`bigint(20) NOTNULL AUTO_INCREMENT COMMENT'主键',
`type`varchar(255) NOTNULLCOMMENT'任务类型',
`data`varchar(255) NOTNULLCOMMENT'任务数据',
`error_message`varchar(255) DEFAULTNULLCOMMENT'错误信息',
`context`varchar(255) DEFAULTNULLCOMMENT'任务上下文(主要是保存当前操作人)',
`create_time`bigint(20) NOTNULLCOMMENT'创建时间',
`update_time`bigint(20) NOTNULLCOMMENT'更新时间',
`retry_times`int(11) NOTNULLDEFAULT'0'COMMENT'重试次数',
PRIMARY KEY (`id`)
) ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='事务任务表';
作用:保存小事务的关键数据到data字段中,以保证通过该字段,就能正确执行小事务。另外也需要保存当前操作人的信息context。
第二步,通过定时任务,查出 transaction_job
表中未完成的数据,并执行对应的操作,这里通过简单的策略模式,将框架代码和业务代码做了分离
首先是框架代码核心逻辑
扫描任务
执行任务
这是一个策略模式接口,每个小事务就封装一个独立的实现类
其中更新待审人的任务实现如下,其实就是把那部分代码复制过来
第三步,改造业务代码,不再一次性把流程写完,而且是在第一个小事务中,顺便往 transaction_job
中插入一条数据,以执行第二个小事务
其中步骤2(插入任务数据的代码)的具体实现如下(
)
transactionJobService.create
优化
上述方案种,除第一个事务外,后续事务都是通过定时任务来执行的,因此这些事务都存在一定的延迟,用户体验不好,解决办法也非常简单,只需要利用好Spring对于事务的生命周期管理,稍微改造一下插入任务的方法(
)
transactionJobService.create
这是Spring提供的工具类, afterCommit()
方法会在事务提交后执行,因此加上这段代码后,思路就变成了这样
如果小事务顺利执行,会立刻将该任务改为“成功”,因此从用户端是感受不到延迟的
注意
可能存在添加任务后,定时任务也立刻扫描到了这条数据,同一任务就会被主线程与定时任务线程同时执行,所以实际应用中需要考虑这个问题(比如:加锁再执行,执行前再检查数据库状态)
结语
目前只给出了解决思路的核心,但真实项目中,还添加了不少额外功能,以后会逐渐更新进来
更多相关网站
- 10个SQL优化技巧,性能提升300%(sql优化从哪几方面入手)
- 面试官问你 MySQL 的线上执行 DDL 该怎么做?...
- MySQL 8.0 的隐藏索引:索引管理的利器,还是性能陷阱?
- MySQL实战:Json字段类型详解(mysql中json类型)
- Spring事务失效的12种解决方案!15年踩坑经验浓缩成这份避雷指南
- 面试官:select语句和update语句分别是怎么执行的?
- 详细了解 InnoDB 内存结构及其原理
- 深度剖析 Spring Boot3 中事务失效的场景与解决方案
- java 使用Jdbc连接mysql数据库以及其存在的问题
- 百万订单背后的架构生死局:SpringCloud Alibaba拯救我们的微服务
- 面试官:20 亿手机号存储选 int 还是 string?varchar 还是 char?
- 面试官:MySQL的自增ID用完了,怎么办?
- 别再用雪花算法生成ID了!试试这个吧
- # mysql 中文乱码问题分析(#mysql5.0中文乱码)
- MySQL分页到了后面越来越慢,有什么好的解决办法?
- Spring Boot3 中实现树表结构数据查询及返回全解析
- SQL外连接优化:经过验证的性能提升
- zPaaS低代码平台使用介绍:第一个功能开发
- 最近发表
- 标签列表
-
- mydisktest_v298 (35)
- sql 日期比较 (33)
- document.appendchild (35)
- 头像打包下载 (35)
- 二调符号库 (23)
- acmecadconverter_8.52绿色版 (25)
- 梦幻诛仙表情包 (36)
- java面试宝典2019pdf (26)
- disk++ (30)
- 加密与解密第四版pdf (29)
- iteye (26)
- centos7.4下载 (32)
- intouch2014r2sp1永久授权 (33)
- usb2.0-serial驱动下载 (24)
- jdk1.8.0_191下载 (27)
- axure9注册码 (30)
- virtualdrivemaster (26)
- 数据结构c语言版严蔚敏pdf (25)
- 兔兔工程量计算软件下载 (27)
- 代码整洁之道 pdf (26)
- ccproxy破解版 (31)
- aida64模板 (28)
- engine=innodb (33)
- shiro jwt (28)
- 方格子excel破解版补丁 (25)