无锡网站开发培训,企业网站模板 html,wordpress 删除评论框,做企业的网站的如何推广seata
SAGA模式#xff1a;
代码仍然是上一篇AT模式的代码#xff1a;AT模式 不需要undo_log表
下面开始#xff1a;
首先#xff0c;saga模式依靠状态机的json文件来执行整个流程#xff0c;其中的开始节点的服务即TM#xff0c;然后状态机需要依靠三张表#xff0…seata
SAGA模式
代码仍然是上一篇AT模式的代码AT模式 不需要undo_log表
下面开始
首先saga模式依靠状态机的json文件来执行整个流程其中的开始节点的服务即TM然后状态机需要依靠三张表 seata_state_inst,seate_state_machine_def,seata_state_machine_inst 建表语句如下注意这三张表需要注册在你的TM服务所属的业务库其余子业务库不需要因为saga原则上是谁先开始TM谁的库负责存状态机的相关信息
-- ----------------------------
-- Table structure for seata_state_inst
-- ----------------------------
DROP TABLE IF EXISTS seata_state_inst;
CREATE TABLE seata_state_inst (id varchar(48) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT id,machine_inst_id varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT state machine instance id,NAME varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT state name,TYPE varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT state type,service_name varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT service name,service_method varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT method name,service_type varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT service type,business_key varchar(48) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT business key,state_id_compensated_for varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT state compensated for,state_id_retried_for varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT state retried for,gmt_started timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT start time,is_for_update tinyint(1) DEFAULT NULL COMMENT is service for update,input_params longtext CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT input parameters,output_params longtext CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT output parameters,STATUS varchar(2) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT status(SU succeed|FA failed|UN unknown|SK skipped|RU running),excep blob COMMENT exception,gmt_end timestamp(3) NOT NULL COMMENT end time,PRIMARY KEY (id, machine_inst_id) USING BTREE
) ENGINE InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci ROW_FORMAT Dynamic;-- ----------------------------
-- Table structure for seata_state_machine_def
-- ----------------------------
DROP TABLE IF EXISTS seata_state_machine_def;
CREATE TABLE seata_state_machine_def (id varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT id,name varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT name,tenant_id varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT tenant id,app_name varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT application name,type varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT state language type,comment_ varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT comment,ver varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT version,gmt_create timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT create time,status varchar(2) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT status(AC:active|IN:inactive),content longtext CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT content,recover_strategy varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT transaction recover strategy(compensate|retry),PRIMARY KEY (id) USING BTREE
) ENGINE InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci ROW_FORMAT Dynamic;-- ----------------------------
-- Table structure for seata_state_machine_inst
-- ----------------------------
DROP TABLE IF EXISTS seata_state_machine_inst;
CREATE TABLE seata_state_machine_inst (id varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT id,machine_id varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT state machine definition id,tenant_id varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT tenant id,parent_id varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT parent id,gmt_started timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT start time,business_key varchar(48) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT business key,start_params longtext CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT start parameters,gmt_end timestamp(3) NOT NULL COMMENT end time,excep blob COMMENT exception,end_params longtext CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT end parameters,STATUS varchar(2) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT status(SU succeed|FA failed|UN unknown|SK skipped|RU running),compensation_status varchar(2) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT compensation status(SU succeed|FA failed|UN unknown|SK skipped|RU running),is_running tinyint(1) DEFAULT NULL COMMENT is running(0 no|1 yes),gmt_updated timestamp(3) NOT NULL,PRIMARY KEY (id) USING BTREE,UNIQUE INDEX unikey_buz_tenant(business_key, tenant_id) USING BTREE
) ENGINE InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci ROW_FORMAT Dynamic;SET FOREIGN_KEY_CHECKS 1;接下来是定义状态机json文件这里官方推荐用那个状态机desinger具体见官网吧需要下下来npm install,npm start 运行起来如图
这里附上我的json文件并简单解释json的程序走向
{nodes: [{type: node,size: 72*72,shape: flow-circle,color: #FA8C16,label: Start,stateId: Start,stateType: Start,stateProps: {StateMachine: {Name: startCreateOrder,Comment: 开始下单,Version: 0.0.1},Next: ReduceGoods},x: 221.60527099609374,y: -133.02889122009276,id: db4c4a01,index: 6},{type: node,size: 110*48,shape: flow-rect,color: #1890FF,label: ReduceGoods,stateId: ReduceGoods,stateType: ServiceTask,stateProps: {Type: ServiceTask,ServiceName: doCreateOrderOperation,ServiceMethod: reduceGoodsCount,Next: ChoiceGoodsState,Input: [$.[businessKey],$.[goodsId]],Output: {ReduceGoodsResult: $.#root},Status: {#root true: SU,#root false: FA,$Exception{java.lang.Throwable}: UN},CompensateState: ReduceGoodsCompensation},x: 221.60527099609374,y: -5.02889122009276,id: ed9b4961,index: 7},{type: node,size: 80*72,shape: flow-rhombus,color: #13C2C2,label: ChoiceGoodsState,stateId: ChoiceGoodsState,stateType: Choice,x: 221.60527099609374,y: 126.47110877990724,id: 882b4bcc,stateProps: {},index: 8},{type: node,size: 110*48,shape: flow-rect,color: #1890FF,label: ReduceMoney,stateId: ReduceMoney,stateType: ServiceTask,stateProps: {CompensateState: ReduceMoneyCompensation,Type: ServiceTask,ServiceName: doCreateOrderOperation,ServiceMethod: reduceMoney,Next: ReduceMoneyState,Input: [$.[businessKey],$.[userId]],Output: {ReduceMoneyResult: $.#root},Status: {#roottrue: SU,#root false: FA,$Exception{java.lang.Throwable}: UN}},x: 222.10527099609374,y: 238.47110877990724,id: e642a93e,index: 9},{type: node,size: 80*72,shape: flow-rhombus,color: #13C2C2,label: ReduceMoneyState,stateId: ReduceMoneyState,stateType: Choice,x: 220.60527099609374,y: 361.47110877990724,id: bb6b3f2e,stateProps: {},index: 10},{type: node,size: 72*72,shape: flow-circle,color: #05A465,label: Succeed,stateId: Succeed,stateType: Succeed,x: 220.60527099609374,y: 851.3333358764648,id: d4e7e04e,stateProps: {Type: Succeed},index: 11},{type: node,size: 110*48,shape: flow-rect,color: #1890FF,label: CreateOrder,stateId: CreateOrder,stateType: ServiceTask,stateProps: {CompensateState: CreateOrderCompensation,Type: ServiceTask,ServiceName: createOrderService,ServiceMethod: createOrder,Next: CreateOrderState,Input: [$.[businessKey],$.[userId],$.[goodsId],$.[goodsCount]],Output: {CreateOrderResult: $.#root},Status: {#roottrue: SU,#root false: FA,$Exception{java.lang.Throwable}: UN}},x: 220.60527099609374,y: 537.9711087799072,id: 101b97df,index: 13},{type: node,size: 110*48,shape: flow-capsule,color: #722ED1,label: ReduceGoods补偿,stateId: ReduceGoodsCompensation,stateType: Compensation,stateProps: {ServiceName: doCreateOrderOperation,ServiceMethod: reduceGoodsCompensation,Input: [$.[businessKey],$.[goodsId]]},x: -43.66667175292969,y: -4.52889122009276,id: 670994f3},{type: node,size: 39*39,shape: flow-circle,color: red,label: ReduceGoodsCatch,stateId: ReduceGoodsCatch,stateType: Catch,x: 278.60527099609374,y: -4.52889122009276,id: 0a75001d},{type: node,size: 110*48,shape: flow-capsule,color: red,label: ReduceGoodsCompensationTrigger,stateId: ReduceGoodsCompensationTrigger,stateType: CompensationTrigger,x: 489.3333282470703,y: -6.333335876464844,id: ea548fae},{type: node,size: 72*72,shape: flow-circle,color: red,label: Fail,stateId: Fail,stateType: Fail,stateProps: {ErrorCode: 666,Message: 全局业务失败},x: 702.3333282470703,y: 138.66666412353516,id: d6d40f5c},{type: node,size: 110*48,shape: flow-capsule,color: #722ED1,label: ReduceMoneyCompensation,stateId: ReduceMoneyCompensation,stateType: Compensation,stateProps: {ServiceName: doCreateOrderOperation,ServiceMethod: reduceMoneyCompensation,Input: [$.[businessKey],$.[userId]]},x: -42.66667175292969,y: 238.97110877990724,id: e0bdb122},{type: node,size: 110*48,shape: flow-capsule,color: red,label: ReduceMoneyCompensationTrigger,stateId: ReduceMoneyCompensationTrigger,stateType: CompensationTrigger,x: 490.1666564941406,y: 239.47110877990724,id: f95c5ba4},{type: node,size: 39*39,shape: flow-circle,color: red,label: ReduceMoneyCatch,stateId: ReduceMoneyCatch,stateType: Catch,x: 277.60527099609374,y: 238.97110877990724,id: 5b0ed40b},{type: node,size: 110*48,shape: flow-capsule,color: #722ED1,label: CreateOrderCompensation,stateId: CreateOrderCompensation,stateType: Compensation,stateProps: {ServiceName: createOrderService,ServiceMethod: createOrderCompensation,Input: [$.[businessKey],$.[userId],$.[goodsId],$.[goodsCount]]},x: -50.333343505859375,y: 538.4711087799072,id: 99eda994},{type: node,size: 39*39,shape: flow-circle,color: red,label: CreateOrderCatch,stateId: CreateOrderCatch,stateType: Catch,x: 276.10527099609374,y: 536.6666641235352,id: bf4f0b7e},{type: node,size: 110*48,shape: flow-capsule,color: red,label: CreateOrderCompensationTrigger,stateId: CreateOrderCompensationTrigger,stateType: CompensationTrigger,x: 521.6666564941406,y: 538.9711087799072,id: 28bf46d3},{type: node,size: 80*72,shape: flow-rhombus,color: #13C2C2,label: CreateOrderState,stateId: CreateOrderState,stateType: Choice,x: 220.60527099609374,y: 675.6666641235352,id: 35113d56,stateProps: {},index: 12}],edges: [{source: db4c4a01,sourceAnchor: 2,target: ed9b4961,targetAnchor: 0,id: 56512448,shape: flow-polyline-round,index: 0},{source: ed9b4961,sourceAnchor: 2,target: 882b4bcc,targetAnchor: 0,id: 02dd82f0,shape: flow-polyline-round,index: 1},{source: 882b4bcc,sourceAnchor: 2,target: e642a93e,targetAnchor: 0,id: 8a20e337,shape: flow-polyline-round,stateProps: {Expression: [ReduceGoodsResult]true,Next: ReduceMoney},index: 2,label: },{source: e642a93e,sourceAnchor: 2,target: bb6b3f2e,targetAnchor: 0,id: d80e333a,shape: flow-polyline-round,index: 3},{source: bb6b3f2e,sourceAnchor: 2,target: 101b97df,targetAnchor: 0,id: c8f07d89,shape: flow-polyline-round,stateProps: {Expression: [ReduceMoneyResult]true,Next: CreateOrder},index: 4,label: },{source: ed9b4961,sourceAnchor: 3,target: 670994f3,targetAnchor: 1,id: 5c40049a,shape: flow-polyline-round,style: {lineDash: 4,endArrow: false},type: Compensation},{source: 0a75001d,sourceAnchor: 1,target: ea548fae,targetAnchor: 3,id: 7f5fff3e,shape: flow-polyline-round,stateProps: {Exceptions: [java.lang.Throwable],Next: ReduceGoodsCompensationTrigger},label: },{source: ea548fae,sourceAnchor: 1,target: d6d40f5c,targetAnchor: 0,id: 9a6fd7e4,shape: flow-polyline-round},{source: 882b4bcc,sourceAnchor: 1,target: ea548fae,targetAnchor: 2,id: ff64d724,shape: flow-polyline-round,stateProps: {Expression: [ReduceGoodsResult]false,Next: ReduceGoodsCompensationTrigger},label: },{source: e642a93e,sourceAnchor: 3,target: e0bdb122,targetAnchor: 1,id: 1be846e4,shape: flow-polyline-round,style: {lineDash: 4,endArrow: false},type: Compensation},{source: 5b0ed40b,sourceAnchor: 1,target: f95c5ba4,targetAnchor: 3,id: 654b410d,shape: flow-polyline-round,stateProps: {Exceptions: [java.lang.Throwable],Next: ReduceMoneyCompensationTrigger},label: },{source: f95c5ba4,sourceAnchor: 1,target: d6d40f5c,targetAnchor: 2,id: ddb6958e,shape: flow-polyline-round},{source: bb6b3f2e,sourceAnchor: 1,target: f95c5ba4,targetAnchor: 2,id: b57c61be,shape: flow-polyline-round,stateProps: {Expression: [ReduceMoneyResult]false,Next: ReduceMoneyCompensationTrigger},label: },{source: 101b97df,sourceAnchor: 3,target: 99eda994,targetAnchor: 1,id: 26d69c8e,shape: flow-polyline-round,style: {lineDash: 4,endArrow: false},type: Compensation},{source: bf4f0b7e,sourceAnchor: 1,target: 28bf46d3,targetAnchor: 3,id: 8983c877,shape: flow-polyline-round,stateProps: {Exceptions: [java.lang.Throwable],Next: CreateOrderCompensationTrigger},label: },{source: 28bf46d3,sourceAnchor: 1,target: d6d40f5c,targetAnchor: 2,id: d781fbc9,shape: flow-polyline-round},{source: 101b97df,sourceAnchor: 2,target: 35113d56,targetAnchor: 0,id: 2e639684,shape: flow-polyline-round},{source: 35113d56,sourceAnchor: 2,target: d4e7e04e,targetAnchor: 0,id: b9bf4a83,shape: flow-polyline-round,stateProps: {Expression: [CreateOrderResult]true,Next: Succeed},label: },{source: 35113d56,sourceAnchor: 1,target: 28bf46d3,targetAnchor: 2,id: 541f04ee,shape: flow-polyline-round,stateProps: {Expression: [CreateOrderResult]false,Next: CreateOrderCompensationTrigger},label: }]
}json解释
首先start节点中的Name是你java代码中调用状态机的标识Next标识下一个运行的节点是ReduceGoods
ReduceGoods节点中是个扣减库存的服务所以Type是ServiceTask、 这里的ServiceName是你注册到spring容器中的服务的bean的名字下面我会给代码全图给你们参考ServiceMethods是上文那个bean中的方法reduceGoodsCountNext是下个节点应该执行的服务input是reduceGoodsCount方法的入参这个businessKey是必要的代码中调用startWithBusinessKey时需要output是服务的输出ReduceGoodsResult这个节点需要和下面的判断节点一致status中我的服务返回的是true和false根据这个判断这个ServiceTask节点是否执行成功 “$Exception{java.lang.Throwable}”: UN代表服务报错CompensateState代表是ReduceGoods的补偿方法在服务失败或报错后的方法一般是补偿操作举个例子就是比如这个服务扣库存了补偿就是加回去
然后看到流程图中的左侧紫色模块这些是服务的补偿服务json中他的Type是Compensation。代表补偿输入和非补偿服务是一样的这个实际业务场景中根据业务而变未必是一样的
ReduceGoods执行完毕后来到ChoiceGoodsState在这里我的判断定义在线条中
Catch
补偿触发器 而选择节点我是空的
ReduceGoods执行成功后的判断
ps 此json的Choice和成功或失败的线条遇到一个坑如果有Choice的两个分支中其中一个的Props写的没对应java代码中调用会报No choice matched, maybe it is a bug. Choice state name: CreateOrderState
其他节点基本和上述一致对应的bean名和方法入参出参补偿方法判断条件相应改变即可
java代码中:
将刚才的json存到你的TM所属服务的resources中
接下来要配config
package com.example.createorder.config;import io.seata.saga.engine.config.DbStateMachineConfig;
import io.seata.saga.engine.impl.ProcessCtrlStateMachineEngine;
import io.seata.saga.rm.StateMachineEngineHolder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.concurrent.ThreadPoolExecutor;Configuration
Component
public class StateMachineConfiguration {Beanpublic ThreadPoolExecutorFactoryBean threadExecutor(){ThreadPoolExecutorFactoryBean threadExecutor new ThreadPoolExecutorFactoryBean();threadExecutor.setThreadNamePrefix(SAGA_ASYNC_EXE_);threadExecutor.setCorePoolSize(1);threadExecutor.setMaxPoolSize(20);return threadExecutor;}Beanpublic DbStateMachineConfig dbStateMachineConfig(ThreadPoolExecutorFactoryBean threadExecutor, DataSource hikariDataSource) throws IOException {DbStateMachineConfig dbStateMachineConfig new DbStateMachineConfig();dbStateMachineConfig.setDataSource(hikariDataSource);dbStateMachineConfig.setThreadPoolExecutor((ThreadPoolExecutor) threadExecutor.getObject());// 这里的setResources如果你用的seata是1.4.1以上版本这里的入参应该是String[],我试了几种方法都加载不进去然后把seata降到了1.4.1dbStateMachineConfig.setResources(new PathMatchingResourcePatternResolver().getResources(classpath*:statelang/*.json));//json文件dbStateMachineConfig.setEnableAsync(true);dbStateMachineConfig.setApplicationId(myfirstsaga);dbStateMachineConfig.setTxServiceGroup(default_tx_group);//这个和我上一篇讲的一致要和你涉及的子事务一致return dbStateMachineConfig;}Beanpublic ProcessCtrlStateMachineEngine stateMachineEngine(DbStateMachineConfig dbStateMachineConfig){ProcessCtrlStateMachineEngine stateMachineEngine new ProcessCtrlStateMachineEngine();stateMachineEngine.setStateMachineConfig(dbStateMachineConfig);return stateMachineEngine;}Beanpublic StateMachineEngineHolder stateMachineEngineHolder(ProcessCtrlStateMachineEngine stateMachineEngine){StateMachineEngineHolder stateMachineEngineHolder new StateMachineEngineHolder();stateMachineEngineHolder.setStateMachineEngine(stateMachineEngine);return stateMachineEngineHolder;}}yml配置
server:port: 3333
spring:application:name: createOrdercloud:nacos:discovery:server-addr: 127.0.0.1:8848ip: 127.0.0.1register-enabled: truedatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/orders?serverTimezoneUTCuseUnicodetruecharacterEncodingutf-8username: rootpassword: roottype: com.alibaba.druid.pool.DruidDataSourcemybatis:mapper-locations: classpath:mappers/*.xmlconfiguration:map-underscore-to-camel-case: truedubbo:application: #应用配置用于配置当前应用信息不管该应用是提供者还是消费者。name: Consumer-createOrderregistry: #注册中心配置用于配置连接注册中心相关信息。address: nacos://127.0.0.1:8848protocol: #协议配置用于配置提供服务的协议信息协议由提供方指定消费方被动接受。name: dubboport: 20880scan:base-packages: com.example.reducegoods.service #服务暴露与发现消费所在的package#
#seata:
## enable-auto-data-source-proxy: true
# enabled: true
# tx-service-group: local_saga
#
# service:
# grouplist:
# seata-server: 127.0.0.1:8091
# vgroupMapping:
# local_saga: default
##
seata:enabled: truetx-service-group: default_tx_groupservice:default:grouplist:seata-server: 127.0.0.1:8091vgroupMapping:default_tx_group: default# saga:
# enabled: true
# state-machine:
# table-prefix: seata_
# enable-async: false
# async-thread-pool:
# core-pool-size: 1
# max-pool-size: 20
# keep-alive-time: 60
# trans-operation-timeout: 1800000
# service-invoke-timeout: 300000
# auto-register-resources: true
# resources:
# - classpath*:statelang/saga.json
# default-tenant-id: 000001
# charset: UTF-8另外的扣库存和扣余额的配置文件 减余额 server:port: 2222
spring:application:name: reduceMoneycloud:nacos:discovery:server-addr: 127.0.0.1:8848ip: 127.0.0.1register-enabled: true# alibaba:
# seata:
# tx-service-group: default_tx_groupdatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/users?serverTimezoneUTCuseUnicodetruecharacterEncodingutf-8username: rootpassword: roottype: com.alibaba.druid.pool.DruidDataSourcemybatis:mapper-locations: classpath:mappers/*.xmlconfiguration:map-underscore-to-camel-case: truedubbo:application: #应用配置用于配置当前应用信息不管该应用是提供者还是消费者。name: reduceMoneyregistry: #注册中心配置用于配置连接注册中心相关信息。address: nacos://127.0.0.1:8848protocol: #协议配置用于配置提供服务的协议信息协议由提供方指定消费方被动接受。name: dubboport: 20881scan:base-packages: com.example.reducemoney.service #服务暴露与发现消费所在的packageseata:enable-auto-data-source-proxy: trueenabled: truetx-service-group: default_tx_groupconfig:type: nacosnacos:server-addr: 127.0.0.1:8848group: SEATA_GROUPnamespace: d23703ee-09aa-444b-83b5-1c7f8ca7a4a7registry:type: nacosnacos:application: seata-serverserver-addr: 127.0.0.1:8848group: SEATA_GROUPnamespace: d23703ee-09aa-444b-83b5-1c7f8ca7a4a7username: password: service:# 事务组对应的集群民称vgroupMapping:default_tx_group: default
减库存
server:port: 1111
spring:application:name: reduceGoodscloud:nacos:discovery:server-addr: 127.0.0.1:8848ip: 127.0.0.1
# register-enabled: true# alibaba:
# seata:
# tx-service-group: default_tx_groupdatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/goods?serverTimezoneUTCuseUnicodetruecharacterEncodingutf-8username: rootpassword: roottype: com.alibaba.druid.pool.DruidDataSourcemybatis:mapper-locations: classpath:mappers/*.xmlconfiguration:map-underscore-to-camel-case: truedubbo:application: #应用配置用于配置当前应用信息不管该应用是提供者还是消费者。name: reduceGoodsregistry: #注册中心配置用于配置连接注册中心相关信息。address: nacos://127.0.0.1:8848protocol: #协议配置用于配置提供服务的协议信息协议由提供方指定消费方被动接受。name: dubboport: 20880scan:base-packages: com.example.reducegoods.service #服务暴露与发现消费所在的packageseata:enable-auto-data-source-proxy: trueenabled: truetx-service-group: default_tx_groupconfig:type: nacosnacos:server-addr: 127.0.0.1:8848group: SEATA_GROUPnamespace: d23703ee-09aa-444b-83b5-1c7f8ca7a4a7registry:type: nacosnacos:application: seata-serverserver-addr: 127.0.0.1:8848group: SEATA_GROUPnamespace: d23703ee-09aa-444b-83b5-1c7f8ca7a4a7username: password: service:# 事务组对应的集群民称vgroupMapping:default_tx_group: default
库存服务代码
package com.example.reducegoods.serviceImpl;import com.example.reducegoods.dao.ReduceGoodsDao;
import com.example.reducegoods.service.ReduceGoodsService;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;Service
Component
public class ReduceGoodsServiceImpl implements ReduceGoodsService {AutowiredReduceGoodsDao reduceGoodsDao;Overridepublic int reduceGoodsCount(String id) {System.out.println(减库存idid);int result 0;try {result reduceGoodsDao.reduceGoodsCount(id);}catch (Exception e){e.printStackTrace();throw e;}return result;}
}
代码结构 余额服务同理注意这个service是dubbo的
接下来是用创建订单服务调用这两个服务 创建订单服务Controller
RestController
public class MakeOrderController {AutowiredCreateOrderService createOrderService;AutowiredStateMachineEngine stateMachineEngine;RequestMapping(/createOrder/{userId}/{goodsId}/{goodsCount})public void createOrder(PathVariable(userId)String userId,PathVariable(goodsId)String goodsId,PathVariable(goodsCount)String goodsCount){MapString, Object startParams new HashMap(4);//唯一健String businessKey String.valueOf(System.currentTimeMillis());startParams.put(businessKey, businessKey);startParams.put(userId, userId);startParams.put(goodsId, goodsId);startParams.put(goodsCount, goodsCount);StateMachineInstance inst stateMachineEngine.startWithBusinessKey(startCreateOrder, null,businessKey,startParams);if(ExecutionStatus.SU.equals(inst.getStatus())){System.out.println(成功inst.getId());}else{System.out.println(失败inst.getId());}}}服务层接口
package com.example.createorder.service;public interface DoCreateOrderOperation {boolean reduceGoodsCount(String businessKey,String goodsId);boolean reduceGoodsCompensation();boolean reduceMoney(String businessKey,String userId);boolean reduceMoneyCompensation();}
package com.example.createorder.service;public interface CreateOrderService {boolean createOrder(String orderId,String userId,String goodsId,String goodsCount);boolean createOrderCompensation();
} DoCreateOrderOpeartionImpl
package com.example.createorder.serviceImpl;import com.example.reducegoods.service.ReduceGoodsService;
import com.example.reducemoney.service.ReduceMoneyService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;Service(doCreateOrderOperation)
public class DoCreateOrderOperationImpl implements com.example.createorder.service.DoCreateOrderOperation {DubboReferenceReduceGoodsService reduceGoodsService;DubboReferenceReduceMoneyService reduceMoneyService;//减库存Overridepublic boolean reduceGoodsCount(String businessKey,String goodsId) {// System.out.println(http调用扣库存接受到的businessKey为businessKey);
// System.out.println(http调用扣库存接受到的goodsid为goodsId);
// resttemplate是http形式调用服务
// String reduceGoodsUrlhttp://reduceGoods/reduceGoods/goodsId;
// String forObject restTemplate.getForObject(reduceGoodsUrl, String.class);// dubbo rpc调用System.out.println(dubbp rpc调用扣库存接受到的businessKey为businessKey);System.out.println(dubbp rpc调用扣库存接受到的goodsid为goodsId);int i reduceGoodsService.reduceGoodsCount(goodsId);if (i1){return true;}else {return false;}}Overridepublic boolean reduceGoodsCompensation() {System.out.println(执行扣减库存补偿操作);return true;}Overridepublic boolean reduceMoney(String businessKey, String userId) {// System.out.println(http调用扣钱接受到的businessKey为businessKey);
// System.out.println(http调用扣钱接受到的userId为userId);
// restttemplate是http调用方式
// String reduceMoneyUrlhttp://reduceMoney/reduceMoney/userId;
// String forObject restTemplate.getForObject(reduceMoneyUrl, String.class);// dubbo rpc调用System.out.println(dubbp rpc调用扣钱接受到的businessKey为businessKey);System.out.println(dubbp rpc调用扣钱接受到的userId为userId);int i reduceMoneyService.reduceRestMoney(userId);if (i1){return true;}else {return false;}}Overridepublic boolean reduceMoneyCompensation() {System.out.println(调用扣减余额的补偿操作);return true;}}
因为在json 中定义的扣库存和扣余额服务是注册在外部的其他spring容器中的所以是在是当前容器中调用其他模块的服务实现相当于套了一层 补偿方法这里没做处理就打印个东西示意
接下来启动三个服务前提是将seata和nacos起起来我这里注册中心用的naocs调用用dubbo rpc 这个CreateOrder服务启动成功后可以在数据库seata_state_machine_def表中看到注册成功的注册机数据 调用流程 扣库存-扣余额-创建订单
一、模拟成功情况 一、模拟第三步创建订单失败情况 可以看到第三步以及之前的步骤都执行了补偿操作如果你在第二步报错那就会执行12步的补偿操作
如果过程中出现safe guard client , should not be called ,must have a bug把dubbo版本升到2.7.12 dependencygroupIdorg.apache.dubbo/groupIdartifactIddubbo-spring-boot-starter/artifactIdversion2.7.12/version/dependency参考 参考1