Seata架构篇 - SAGA模式
创始人
2025-05-29 03:05:40
0

SAGA模式

Saga 模式是 Seata 提供的长事务解决方案,在 Saga 模式中,业务流程中每个参与者都提交本地事务,当某个参与者出现失败,则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都有业务开发实现。

Saga模式示意图

适用场景

业务流程长、业务流程多。

参与者包含其它公司或者遗留系统服务,无法提供 TCC 模式要求的三个接口。

原理

SEATA提供的Saga模式是基于状态机引擎来实现的,机制是:

  1. 通过状态图来定义服务调用的流程并生成 json 状态语言定义文件
  2. 状态图中一个节点可以是调用一个服务,节点可以配置它的补偿节点
  3. 状态图 json 由状态机引擎驱动执行,当出现异常时状态引擎反向执行已成功节点对应的补偿节点将事务回滚

注意: 异常发生时是否进行补偿也可由用户自定义决定

  1. 可以实现服务编排需求,支持单项选择、并发、子流程、参数转换、参数映射、服务执行状态判断、异常捕获等功能

使用

@GetMapping("/test_saga")
public String testSaga() {Map startParams = new HashMap<>(3);String businessKey = String.valueOf(System.currentTimeMillis());startParams.put("businessKey", businessKey);startParams.put("count", 10);startParams.put("amount", new BigDecimal("100"));// 模拟compensate//startParams.put("mockReduceBalanceFail", "true");StateMachineInstance inst = stateMachineEngine.startWithBusinessKey("reduceInventoryAndBalance", null,businessKey, startParams);Assert.isTrue(ExecutionStatus.SU.equals(inst.getStatus()),"saga transaction execute failed. XID: " + inst.getId());System.out.println("saga transaction commit succeed. XID: " + inst.getId());return "finished";
}

在 resources/statelang 目录下创建一个 reduce_inventory_and_balance.json 文件。

{"Name": "reduceInventoryAndBalance","Comment": "reduce inventory then reduce balance in a transaction","StartState": "ReduceInventory","Version": "0.0.1","States": {"ReduceInventory": {"Type": "ServiceTask","ServiceName": "inventoryAction","ServiceMethod": "reduce","CompensateState": "CompensateReduceInventory","Next": "ChoiceState","Input": ["$.[businessKey]","$.[count]"],"Output": {"reduceInventoryResult": "$.#root"},"Status": {"#root == true": "SU","#root == false": "FA","$Exception{java.lang.Throwable}": "UN"}},"ChoiceState": {"Type": "Choice","Choices": [{"Expression": "[reduceInventoryResult] == true","Next": "ReduceBalance"}],"Default": "Fail"},"ReduceBalance": {"Type": "ServiceTask","ServiceName": "balanceAction","ServiceMethod": "reduce","CompensateState": "CompensateReduceBalance","Input": ["$.[businessKey]","$.[amount]",{"throwException": "$.[mockReduceBalanceFail]"}],"Output": {"compensateReduceBalanceResult": "$.#root"},"Status": {"#root == true": "SU","#root == false": "FA","$Exception{java.lang.Throwable}": "UN"},"Catch": [{"Exceptions": ["java.lang.Throwable"],"Next": "CompensationTrigger"}],"Next": "Succeed"},"CompensateReduceInventory": {"Type": "ServiceTask","ServiceName": "inventoryAction","ServiceMethod": "compensateReduce","Input": ["$.[businessKey]"]},"CompensateReduceBalance": {"Type": "ServiceTask","ServiceName": "balanceAction","ServiceMethod": "compensateReduce","Input": ["$.[businessKey]"]},"CompensationTrigger": {"Type": "CompensationTrigger","Next": "Fail"},"Succeed": {"Type": "Succeed"},"Fail": {"Type": "Fail","ErrorCode": "PURCHASE_FAILED","Message": "purchase failed"}}
}

BalanceAction

public interface BalanceAction {boolean reduce(String businessKey, BigDecimal amount, Map params);boolean compensateReduce(String businessKey, Map params);}

BalanceActionImpl

@Service("balanceAction")
public class BalanceActionImpl implements BalanceAction {private static final Logger LOGGER = LoggerFactory.getLogger(BalanceActionImpl.class);@Overridepublic boolean reduce(String businessKey, BigDecimal amount, Map params) {if(params != null) {Object throwException = params.get("throwException");if (throwException != null && "true".equals(throwException.toString())) {throw new RuntimeException("reduce balance failed");}}LOGGER.info("reduce balance succeed, amount: " + amount + ", businessKey:" + businessKey);return true;}@Overridepublic boolean compensateReduce(String businessKey, Map params) {if(params != null) {Object throwException = params.get("throwException");if (throwException != null && "true".equals(throwException.toString())) {throw new RuntimeException("compensate reduce balance failed");}}LOGGER.info("compensate reduce balance succeed, businessKey:" + businessKey);return true;}
}

InventoryAction

public interface InventoryAction {boolean reduce(String businessKey, int count);boolean compensateReduce(String businessKey);
}

InventoryActionImpl

@Service("inventoryAction")
public class InventoryActionImpl implements InventoryAction {private static final Logger LOGGER = LoggerFactory.getLogger(InventoryActionImpl.class);@Overridepublic boolean reduce(String businessKey, int count) {LOGGER.info("reduce inventory succeed, count: " + count + ", businessKey:" + businessKey);return true;}@Overridepublic boolean compensateReduce(String businessKey) {LOGGER.info("compensate reduce inventory succeed, businessKey:" + businessKey);return true;}
}

ITAccountService

public interface ITAccountService extends IService {ObjectResponse decreaseAccount(AccountDTO accountDTO);void testGlobalLock();
}

TAccountServiceImpl

@Service
public class TAccountServiceImpl extends ServiceImpl implements ITAccountService {@Overridepublic ObjectResponse decreaseAccount(AccountDTO accountDTO) {int account = baseMapper.decreaseAccount(accountDTO.getUserId(), accountDTO.getAmount().doubleValue());ObjectResponse response = new ObjectResponse<>();if (account > 0) {response.setStatus(RspStatusEnum.SUCCESS.getCode());response.setMessage(RspStatusEnum.SUCCESS.getMessage());return response;}response.setStatus(RspStatusEnum.FAIL.getCode());response.setMessage(RspStatusEnum.FAIL.getMessage());return response;}@Override@GlobalLock@Transactional(rollbackFor = {Throwable.class})public void testGlobalLock() {baseMapper.testGlobalLock("1");System.out.println("Hi, i got lock, i will do some thing with holding this lock.");}
}
                
            
            
            
            
            
            

相关内容

热门资讯

【MapGIS精品教程】012... 文章目录 一、DEM概述二、DEM建立1. 创建规则格网Grid2. 创建不规则三角网Tin 三、数...
深度学习(21)——关于训练过... 深度学习(21)——关于训练过程中loss和acc固若磐石 1. 背景描...
【视频】当端午遇见“六一”,清... 当粽香四溢的端午佳节邂逅童趣满满的六一儿童节,一场别开生面的奇妙之旅即将在清远拉开帷幕!5月31日至...
以文旅为桨,向世界扬帆,202... 极目新闻记者 邬晓芳 通讯员 武旅信 5月29日,2025年武汉市导游大赛在洪山宾馆圆满落幕。本次大...
和姐妹去北京旅游五天四晚需要多... 北京,这座融合了古典与现代的城市,以其独特的风景吸引着世界各地的游客。长城蜿蜒起伏,如同巨龙般壮观;...
潮汕四天三晚旅游攻略,潮汕旅游... 潮汕四天三晚旅游攻略,潮汕旅游4天3晚 作为一个对各地美食和独特文化充满好奇的旅行者,我一直对潮汕这...
Python逆向及相关知识 今天第二次看见python字节码的逆向题,然后发现了一个介绍Python逆向的文章&#...
计算结构体大小-结构体内存对齐... 前言:内容包括:计算结构体大小的详解,修改默认对齐数&#x...
OpenCV 鼠标绘图 1、实验目标 (1)、鼠标当笔 (2)、函数:setMouseCallback() (3)、滑动调色...
【数据分析】ChatGPT可以... ChatGPT可以自动完成哪些数据科学领域的任务?1. 使用ChatGPT为机器学习模...
端午逢六一 避暑在黑河丨粽香游... 端午节作为中国四大传统节日之一,不仅是我国首个入选世界非遗的节日,更是集欢庆娱乐与特色饮食于一体的民...
赛里木湖:大西洋最后一滴眼泪,... 赛里木湖:大西洋最后一滴眼泪,邂逅蓝色梦幻之境 在广袤无垠的西北大地,天山山脉犹如一条巨龙横亘其中。...
暑假去黄山旅游五天四晚花多少钱... 黄山,这座被誉为“天下第一奇山”的名山,以其独特的奇松、怪石、云海、温泉四绝闻名于世,一直是无数旅行...
江西四日游自由行攻略,江西纯玩... 江西这片土地,有着深厚的历史文化底蕴,也有着如诗如画的自然风光。无论是巍峨的庐山,还是灵动的婺源,都...
和爸妈去黄山玩3天人均花多少钱... 黄山,这座被誉为“天下第一奇山”的名山,以其奇松、怪石、云海、温泉四绝闻名于世。一直以来,它都是我心...
潮汕旅游五日游费用,潮汕五天游... 潮汕旅游五日游费用,潮汕五天游怎样安排路线 作为一个对各地风土人情充满好奇的旅行者,潮汕这片充满神秘...
重庆5天游旅游跟团多少钱,重庆... 重庆5天游旅游跟团多少钱,重庆五日游最佳旅游路线攻略 作为一名热爱探索的旅行者,我一直对重庆这座充满...
宜昌三峡3天旅游攻略,宜昌三峡... 宜昌三峡3天旅游攻略,宜昌三峡纯玩3天人均花多少钱? 作为一名热爱自然风光的旅行爱好者,我一直对长江...
宜昌三峡3日游省钱攻略,这一篇... 宜昌三峡3日游省钱攻略,这一篇攻略够你玩转宜昌三峡! 一直对宜昌三峡的美景心心念念,那壮丽的三峡风光...