跳至主要內容

微服务辅助技术-2

wangdx大约 22 分钟

SpringCloudConfig 整合 Nacos

1、
yootk:
  message:
    flag: dev
    content: 沐言科技:www.yootk.com
yootk:
  message:
    flag: test
    content: 李兴华高薪就业编程训练营:edu.yootk.com
yootk:
  message:
    flag: prod
    content: 课程资源下载:www.yootk.com/resources

@Data
@Component // 必须添加为Bean
@RefreshScope // 动态加载
public class MessageConfig {
    @Value("${yootk.message.flag}") // 配置文件的加载KEY
    private String flag;
    @Value("${yootk.message.content}") // 配置文件的加载KEY
    private String content;
}


2、
spring: # Spring配置项
  application:
    name: message.provider # 应用名称
  profiles:
    active: dev # 使用的profile配置项
  cloud: # SpringCloud配置项
    nacos: # Nacos注册中心的配置
      config: # gRPC通讯配置
        server-addr: nacos-server:8848 # Nacos地址
        namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间ID
        group: MICROCLOUD_GROUP # 一般建议大写
        cluster-name: MuyanCluster # 配置集群名称
        username: muyan # 用户名
        password: yootk # 密码
        file-extension: yml # 配置文件类型
      discovery: # 发现服务
        weight: 80
        service: ${spring.application.name} # 使用微服务的名称作为注册的服务名称
        server-addr: nacos-server:8848 # Nacos服务地址
        namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间ID
        group: MICROCLOUD_GROUP # 一般建议大写
        cluster-name: MuyanCluster # 配置集群名称
        username: muyan # 用户名
        password: yootk # 密码
        metadata: # 根据自身的需要配置元数据
          version: 1.0 # 自定义元数据项
          company: 沐言科技 # 自定义元数据项
          url: www.yootk.com # 自定义元数据项
          author: 李兴华(爆可爱的小李老师) # 自定义元数据项


3、
project(":provider-message-8201") {    // 消息微服务
    dependencies {
        implementation("org.springframework.boot:spring-boot-starter-web")
        implementation(libraries.'spring-boot-admin-starter-client')
        // 以下的依赖库为Nacos注册中心所需要的依赖配置
        implementation('com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery') {
            exclude group: 'com.alibaba.nacos', module: 'nacos-client' // 移除旧版本的Nacos依赖
        }
        implementation('com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config') {
            exclude group: 'com.alibaba.nacos', module: 'nacos-client' // 移除旧版本的Nacos依赖
        }
        implementation(libraries.'nacos-client') // 引入与当前的Nacos匹配的依赖库
    }
}

Seata 分布式事务简介

雇员微服务

Seata 服务安装与配置

1、
vi /etc/sysconfig/network-scripts/ifcfg-ens33

2、
IPADDR=192.168.190.191


3、
vi /etc/hostname
vi /etc/hosts
4、
service mysqld start

5、
/usr/local/mysql/bin/mysql -uroot -pmysqladmin

6、
CREATE DATABASE seata CHARACTER SET UTF8;

7、
use seata

8、
b860e2f4-1ec2-4a43-b895-5f89869dd5f0

9、
tar xzvf /var/ftp/seata-server-1.4.2.tar.gz -C /usr/local/

10、
vi /usr/local/seata/seata-server-1.4.2/conf/registry.conf

registry {
  type = "nacos"
  nacos {
    application = "seata-server"
    serverAddr = "192.168.113.17:8848"
    group = "SEATA_GROUP"
    namespace = "b860e2f4-1ec2-4a43-b895-5f89869dd5f0"
    cluster = "SeataCluster"
    username = "nacos"
    password = "nacos"
  }
}

11、

vi /usr/local/seata/seata-server-1.4.2/conf/file.conf

store {
  mode = "db"
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"
    ## if using mysql to store the data, recommend add rewriteBatchedStatements=true in jdbc connection param
    url = "jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true"
    user = "root"
    password = "mysqladmin"
    minConn = 5
    maxConn = 100
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }
}

12、
mv /usr/local/seata/seata-server-1.4.2/lib/jdbc/mysql-connector-java-8.0.19.jar /usr/local/seata/seata-server-1.4.2/lib/

13、
/usr/local/seata/seata-server-1.4.2/bin/seata-server.sh > /usr/local/seata/seata-server-1.4.2/logs/seata.log 2>&1 &

14、
firewall-cmd --zone=public --add-port=8091/tcp --permanent
firewall-cmd --reload


15、
vi /usr/local/seata/seata-server-1.4.2/config.txt
store.mode=db
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=mysqladmin

16、
cd /usr/local/seata/seata-server-1.4.2/bin/

17、
sh /usr/local/seata/seata-server-1.4.2/bin/nacos-config.sh -h 192.168.113.17 -p 8848 -t b860e2f4-1ec2-4a43-b895-5f89869dd5f0 -g SEATA_GROUP -u nacos -w nacos

AT 模式

XA 模式

  • 在 Seata 之中还提供有一种 XA 控制模式,该模式是直接通过数据库的 XA 机制实现的。在此类模式中同样不需要开发者编写大量的事务处理逻辑,一切全部交由 Seata 处理而实现其操作的过程中只需要将项目中使用的 DruidDataSource 更换为 DataSourceProxyXA 接口对象实例即可
CREATE TABLE IF NOT EXISTS `undo_log`
(
    `branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',
    `xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',
    `context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
    `rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',
    `log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',
    `log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',
    `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';
ALTER TABLE `undo_log` ADD INDEX `ix_log_created` (`log_created`);
1、
CREATE TABLE IF NOT EXISTS `undo_log`(
    `branch_id`       BIGINT(20)   NOT NULL COMMENT 'branch transaction id',
    `xid`              VARCHAR(100) NOT NULL COMMENT 'global transaction id',
    `context`         VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
    `rollback_info`  LONGBLOB     NOT NULL COMMENT 'rollback info',
    `log_status`      INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',
    `log_created`     DATETIME(6)  NOT NULL COMMENT 'create datetime',
    `log_modified`    DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';


2、
// https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-seata
implementation group: 'com.alibaba.cloud', name: 'spring-cloud-starter-alibaba-seata', version: '2021.1'
implementation group: 'io.seata', name: 'seata-spring-boot-starter', version: '1.4.2'
// https://mvnrepository.com/artifact/io.seata/seata-spring-boot-starter
implementation group: 'io.seata', name: 'seata-spring-boot-starter', version: '2.0.0'


3、
ext.versions = [                // 定义全部的依赖库版本号
    cloudSeata                : '2021.1',
    seata                : '1.4.2',
]
ext.libraries = [            // 依赖库引入配置
    // 以下的配置为Seata相关的依赖库
    'spring-cloud-starter-alibaba-seata' : "com.alibaba.cloud:spring-cloud-starter-alibaba-seata:${versions.cloudSeata}",
    'seata-spring-boot-starter'' : "io.seata:seata-spring-boot-starter:${versions.seata}"
]


4、
seata:
  application-id: seata-server # Seata应用的名称
  tx-service-group: my_test_tx_group # 事务组,config.txt配置
  service:
    vgroup-mapping: # 事务群组的映射配置
      my_test_tx_group: SeataCluster # 集群名称
  config:
    nacos:
      server-addr: nacos-server:8848 # Nacos服务地址
      namespace: b860e2f4-1ec2-4a43-b895-5f89869dd5f0 # Seata的NameSpace地址
      group: SEATA_GROUP
      username: nacos
      password: nacos
  registry:
    type: nacos # 基于Nacos实现分布式事务管理
    nacos:
      server-addr: nacos-server:8848 # Nacos服务地址
      namespace: b860e2f4-1ec2-4a43-b895-5f89869dd5f0 # Seata的NameSpace地址
      group: SEATA_GROUP
      username: nacos
      password: nacos
      cluster: SeataCluster
      application: seata-server


5、

package com.yootk.consumer.action;

import com.yootk.common.dto.DeptDTO;
import com.yootk.common.dto.EmpDTO;
import com.yootk.service.IDeptService;
import com.yootk.service.IEmpService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/consumer/company/*")
public class CompanyConsumerAction {
    @Autowired
    private IDeptService deptService;
    @Autowired
    private IEmpService empService;
    @GetMapping("add")
    @GlobalTransactional // 全局事务控制
    public Object add(DeptDTO dept, EmpDTO emp) {
        Map<String, Object> result = new HashMap<>(); // 保存最终的及诶过
        this.deptService.add(dept); // 调用部门微服务
        result.put("dept", dept); // 保存结果
        // 此时是没有具体的部门编号返回的,因为在创建微服务的时候没有获取,模拟一下
        emp.setDeptno(dept.getDeptno()); // 获取部门编号
        String ename = emp.getEname(); // 获取要增加的雇员姓名
        for (int x = 0; x < 3; x++) {
            emp.setEmpno(emp.getEmpno() + x);
            emp.setEname(ename + " - " + x);
            this.empService.add(emp); // 3次微服务调用
            result.put("emp-" + x, emp);
        }
        return result;
    }
}


6、
http://consumer-springboot-80/consumer/company/add?empno=70&ename=小李&salary=800.0&deptno=1&deptno=88&dname=AT测试部&loc=洛阳

7、
package com.yootk.provider.config;

import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.xa.DataSourceProxyXA;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class XADataSourceConfiguration {
    @Bean("dataSourceProxy")
    public DataSource dataSource(DruidDataSource druidDataSource) {
        return new DataSourceProxyXA(druidDataSource);
    }
}

TCC 模式

1、
package com.yootk.common.util.tcc;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class TCCResultStore { // TCC状态存储
    // 考虑到实际的开发之中会有多个线程进行TCC的状态操作,所以需要存在有一个xid的存储集合
    private static final Map<Class<?>, Map<String, String>> RESULT_MAP = new ConcurrentHashMap<>(); // 定义存储状态
    public static void setResult(Class<?> tccClass, String xid, String v) {    // 分布式事务数据存储
        Map<String, String> results = RESULT_MAP.get(tccClass); // 判断是否有指定的TCC类型
        if (results == null) {  // 没有数据集合
            synchronized (RESULT_MAP) { // 同步处理
                if (results == null) {
                    results = new ConcurrentHashMap<>();
                    RESULT_MAP.put(tccClass, results); // 保存集合数据
                }
            }
        }
        results.put(xid, v); // 保存当前的分布式事务id
    }
    public static String getResult(Class<?> tccClass, String xid) {
        Map<String, String> results = RESULT_MAP.get(tccClass);
        if (results != null) {
            return results.get(xid);
        }
        return null;
    }
    public static void removeResult(Class<?> tccClass, String xid) {
        Map<String, String> results = RESULT_MAP.get(tccClass);
        if (results != null) {
            results.remove(xid);
        }
    }
}


2、
package com.yootk.provider.tcc;

import com.yootk.common.dto.DeptDTO;
import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;

@LocalTCC // 开启本地事务处理
public interface IDeptTCC {
    @TwoPhaseBusinessAction(name = "deptTCCService", commitMethod = "commit", rollbackMethod = "rollback")
    public boolean prepareAdd(BusinessActionContext businessActionContext,
                              @BusinessActionContextParameter(paramName = "dept") DeptDTO dto);
    public boolean commit(BusinessActionContext businessActionContext);
    public boolean rollback(BusinessActionContext businessActionContext);
}


3、
package com.yootk.provider.tcc.impl;

import com.alibaba.fastjson.JSONObject;
import com.yootk.common.dto.DeptDTO;
import com.yootk.common.util.DeepBeanUtils;
import com.yootk.common.util.tcc.TCCResultStore;
import com.yootk.provider.dao.IDeptDAO;
import com.yootk.provider.tcc.IDeptTCC;
import com.yootk.provider.vo.Dept;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class DeptTCCImpl implements IDeptTCC {
    @Autowired
    private IDeptDAO deptDAO; // 直接实现数据层的处理
    @Override
    public boolean prepareAdd(BusinessActionContext businessActionContext, DeptDTO dto) {
        log.info("【第一阶段】xid = {}、dept = {}", businessActionContext.getXid(), dto);
        // 此时的数据要进行第一阶段的验证,下面是对该数据的简单验证,尝试一下能否使用
        if (dto.getDname() == null || "".equals(dto.getDname())) {
            throw new RuntimeException("部门信息错误"); // 手工抛出异常
        }
        TCCResultStore.setResult(getClass(), businessActionContext.getXid(), "d");
        return true;
    }

    @Override
    public boolean commit(BusinessActionContext businessActionContext) {
        // 将接收到的数据以JSONObject的形式返回,而后通过FastJSON的操作将其转为对象实例
        DeptDTO dept = ((JSONObject)businessActionContext.getActionContext("dept")).toJavaObject(DeptDTO.class);
        log.info("【第二阶段】事务提交,xid = {}、dept = {}",businessActionContext.getXid(), dept);
        // 需要根据第一阶段的prepareAdd()方法来决定是否提交
        if (TCCResultStore.getResult(getClass(),
                businessActionContext.getXid()) == null) { // 防止重复提交
            return true;
        }
        Dept deptVO = new Dept(); // 创建VO类对象
        DeepBeanUtils.copyProperties(dept, deptVO); // 属性拷贝
        try {
            return this.deptDAO.insert(deptVO) > 0;
        } finally {
            TCCResultStore.removeResult(getClass(), businessActionContext.getXid());
        }
    }

    @Override
    public boolean rollback(BusinessActionContext businessActionContext) {
        DeptDTO dept = ((JSONObject)businessActionContext.getActionContext("dept")).toJavaObject(DeptDTO.class);
        log.info("【第二阶段】事务回滚,xid = {}、dept = {}",businessActionContext.getXid(), dept);
        if (TCCResultStore.getResult(getClass(),
                businessActionContext.getXid()) == null) { // 防止重复提交
            return true;
        }
        TCCResultStore.removeResult(getClass(), businessActionContext.getXid());
        return true;
    }
}


4、
package com.yootk.provider.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yootk.common.dto.DeptDTO;
import com.yootk.common.util.DeepBeanUtils;
import com.yootk.provider.dao.IDeptDAO;
import com.yootk.provider.tcc.IDeptTCC;
import com.yootk.provider.vo.Dept;
import com.yootk.service.IDeptService;
import io.seata.rm.tcc.api.BusinessActionContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class DeptServiceImpl implements IDeptService {
    @Autowired
    private IDeptDAO deptDAO;
    @Autowired
    private IDeptTCC deptTCC; // Seata操作
    @Override
    public DeptDTO get(long id) {
        DeptDTO dto = new DeptDTO(); // 实例化传输对象
        // 在本地端通过了VO类实现了数据的加载,随后将此数据拷贝到DTO对象之中
        BeanUtils.copyProperties(this.deptDAO.selectById(id), dto); // 属性拷贝
        return dto;
    }

    @Override
    public boolean add(DeptDTO dto) {
        return this.deptTCC.prepareAdd(new BusinessActionContext(), dto);
    }

    @Override
    public List<DeptDTO> list() {
        QueryWrapper<Dept> wrapper = new QueryWrapper<>();
        List<DeptDTO> allDepts = DeepBeanUtils.copyListProperties(
                this.deptDAO.selectList(wrapper), DeptDTO::new); // 集合数据拷贝
        return allDepts;
    }

    @Override
    public Map<String, Object> split(int currentPage, int lineSize, String column, String keyword) {
        QueryWrapper<Dept> wrapper = new QueryWrapper<>();
        wrapper.like(column, keyword); // 设置模糊查询操作
        int count = this.deptDAO.selectCount(wrapper); // 统计个数
        // 实现数据的查询处理
        IPage<Dept> page = this.deptDAO.selectPage(new Page<>(currentPage, lineSize, count), wrapper);
        Map<String, Object> map = new HashMap<>(); // 包装返回结果
        map.put("allDepts", DeepBeanUtils.copyListProperties(page.getRecords(), DeptDTO::new));
        map.put("allRecorders", page.getTotal());
        map.put("allPages", page.getPages());
        return map;
    }
}


5、
package com.yootk.provider.tcc;

import com.yootk.common.dto.EmpDTO;
import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;

@LocalTCC
public interface IEmpTCC { // 雇员TCC操作
    @TwoPhaseBusinessAction(name="empTCCService", commitMethod = "commit", rollbackMethod = "rollback")
    public boolean prepareAdd(BusinessActionContext businessActionContext,
                              @BusinessActionContextParameter(paramName = "emp") EmpDTO emp);
    public boolean commit(BusinessActionContext businessActionContext);
    public boolean rollback(BusinessActionContext businessActionContext);
}


6、
package com.yootk.provider.tcc;

import com.alibaba.fastjson.JSONObject;
import com.yootk.common.dto.EmpDTO;
import com.yootk.common.util.DeepBeanUtils;
import com.yootk.common.util.tcc.TCCResultStore;
import com.yootk.provider.dao.IEmpDAO;
import com.yootk.provider.vo.Emp;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class EmpTCCImpl implements IEmpTCC{
    @Autowired
    private IEmpDAO empDAO;
    @Override
    public boolean prepareAdd(BusinessActionContext businessActionContext, EmpDTO emp) {
        log.info("【第一阶段】xid = {}、emp = {}", businessActionContext.getXid(), emp);
        // 对当前的操作数据进行验证,此时先尝试一下要增加的雇员的ID是否存在
        if (this.empDAO.selectById(emp.getEmpno()) != null) {
            throw new RuntimeException("雇员信息已经存在。");
        }
        TCCResultStore.setResult(getClass(), businessActionContext.getXid(), "e");
        return true;
    }

    @Override
    public boolean commit(BusinessActionContext businessActionContext) {
        EmpDTO emp = ((JSONObject) businessActionContext.getActionContext("emp")).toJavaObject(EmpDTO.class);
        log.info("【第二阶段】事务提交,xid = {}、emp = {}", businessActionContext.getXid(), empDAO);
        if (TCCResultStore.getResult(getClass(), businessActionContext.getXid()) == null) {
            return true;
        }
        Emp empVO = new Emp();
        DeepBeanUtils.copyProperties(emp, empVO);
        try {
            return this.empDAO.insert(empVO) > 0;
        } finally {
            TCCResultStore.removeResult(getClass(), businessActionContext.getXid());
        }
    }

    @Override
    public boolean rollback(BusinessActionContext businessActionContext) {
        EmpDTO emp = ((JSONObject) businessActionContext.getActionContext("emp")).toJavaObject(EmpDTO.class);
        log.info("【第二阶段】事务回滚,xid = {}、emp = {}", businessActionContext.getXid(), empDAO);
        if (TCCResultStore.getResult(getClass(), businessActionContext.getXid()) == null) {
            return true;
        }
        TCCResultStore.removeResult(getClass(), businessActionContext.getXid());
        return true;
    }
}


7、
package com.yootk.provider.service.impl;

import com.yootk.common.dto.EmpDTO;
import com.yootk.provider.tcc.IEmpTCC;
import com.yootk.service.IEmpService;
import io.seata.rm.tcc.api.BusinessActionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class EmpServiceImpl implements IEmpService {
    @Autowired
    private IEmpTCC empTCC;
    @Override
    public boolean add(EmpDTO dto) {
        return this.empTCC.prepareAdd(new BusinessActionContext(), empTCC);
    }
}


8、
USE yootk8003;
DROP TABLE undo_log;

USE yootk8006;
DROP TABLE undo_log;
9、


Saga 模式

1、
git clone https://github.com/seata/seata.git

2、
seata\saga\seata-saga-statemachine-designer

3、npm install

4、npm start

5、
{
  "StateMachine": {
    "Name": "CompanyService",
    "Comment": "公司人事业务",
    "Version": "0.0.1"
  }
}

6、
{
  "ServiceName": "deptSaga",
  "ServiceMethod": "reduce",
  "Input": [
    "$.[businessKey]",
    "$.[dept]"
  ],
  "Output": {
    "deptServiceReduceResult": "$.#root"
  },
  "Status": {
    "#root == true": "SU",
    "#root == false": "FA",
    "#Exception{java.lang.Throwable}": "UN"
  },
  "Retry": []
}

7、
{
  "ErrorCode": "500",
  "Message": "业务信息错误,人事数据增加失败"
}

8、

{
  "ServiceName": "deptSaga",
  "ServiceMethod": "compensateReduce",
  "Input": [
    "$.[businessKey]",
    "$.[dept]"
  ],
  "Output": {
"deptServiceCompensationResult": "$.#root"
},
  "Status": {
"#root == true": "SU",
    "#root == false": "FA",
    "#Exception{java.lang.Throwable}": "UN"
},
  "Retry": []
}

9、
{
  "ServiceName": "empSaga",
  "ServiceMethod": "reduce",
  "Input": [
    "$.[businessKey]",
    "$.[emp]"
  ],
  "Output": {
    "empServiceReduceResult": "$.#root"
  },
  "Status": {
    "#root == true": "SU",
    "#root == false": "FA",
    "#Exception{java.lang.Throwable}": "UN"
  },
  "Retry": []
}

10、
{
  "ServiceName": "empSaga",
  "ServiceMethod": "compensateReduce",
  "Input": [
    "$.[businessKey]",
    "$.[emp]"
  ],
  "Output": {
    "empServiceCompensationResult": "$.#root"
  },
  "Status": {
    "#root == true": "SU",
    "#root == false": "FA",
    "#Exception{java.lang.Throwable}": "UN"
  },
  "Retry": []
}

11、
{
  "Expression": "[empServiceReduceResult]==true",
  "Next": "SuccessHandle"
}

12、
{
  "nodes": [
    {
      "type": "node",
      "size": "72*72",
      "shape": "flow-circle",
      "color": "#FA8C16",
      "label": "人事业务",
      "stateId": "Start1",
      "stateType": "Start",
      "stateProps": {
        "StateMachine": {
          "Name": "CompanyService",
          "Comment": "公司人事业务",
          "Version": "0.0.1"
        }
      },
      "x": 575.6666564941406,
      "y": 280.99999618530273,
      "id": "dea8dc26",
      "index": 0
    },
    {
      "type": "node",
      "size": "110*48",
      "shape": "flow-rect",
      "color": "#1890FF",
      "label": "部门业务",
      "stateId": "DeptServiceTask",
      "stateType": "ServiceTask",
      "stateProps": {
        "ServiceName": "deptSaga",
        "ServiceMethod": "reduce",
        "Input": [
          "$.[businessKey]",
          "$.[dept]"
        ],
        "Output": {
          "deptServiceReduceResult": "$.#root"
        },
        "Status": {
          "#root == true": "SU",
          "#root == false": "FA",
          "#Exception{java.lang.Throwable}": "UN"
        },
        "Retry": []
      },
      "x": 575.6666564941406,
      "y": 385.49999618530273,
      "id": "15b79f30",
      "index": 1
    },
    {
      "type": "node",
      "size": "39*39",
      "shape": "flow-circle",
      "color": "red",
      "label": "部门异常",
      "stateId": "Catch1",
      "stateType": "Catch",
      "x": 637.0555572509766,
      "y": 384.88888931274414,
      "id": "89b2c29f"
    },
    {
      "type": "node",
      "size": "110*48",
      "shape": "flow-capsule",
      "color": "red",
      "label": "部门补偿触发",
      "stateId": "DeptCompensationTrigger",
      "stateType": "CompensationTrigger",
      "x": 833.5555572509766,
      "y": 384.88888931274414,
      "id": "f483f1ad"
    },
    {
      "type": "node",
      "size": "72*72",
      "shape": "flow-circle",
      "color": "red",
      "label": "业务失败",
      "stateId": "Fail1",
      "stateType": "Fail",
      "stateProps": {
        "ErrorCode": "500",
        "Message": "业务信息错误,人事数据增加失败"
      },
      "x": 979.0555572509766,
      "y": 503,
      "id": "144efa41"
    },
    {
      "type": "node",
      "size": "80*72",
      "shape": "flow-rhombus",
      "color": "#13C2C2",
      "label": "部门判断",
      "stateId": "Choice1",
      "stateType": "Choice",
      "x": 575.6666564941406,
      "y": 488,
      "id": "fbf4f55f"
    },
    {
      "type": "node",
      "size": "110*48",
      "shape": "flow-capsule",
      "color": "#722ED1",
      "label": "部门业务补偿",
      "stateId": "deptCompensation",
      "stateType": "Compensation",
      "stateProps": {
        "ServiceName": "deptSaga",
        "ServiceMethod": "compensateReduce",
        "Input": [
          "$.[businessKey]",
          "$.[dept]"
        ],
        "Output": {
          "deptServiceCompensationResult": "$.#root"
        },
        "Status": {
          "#root == true": "SU",
          "#root == false": "FA",
          "#Exception{java.lang.Throwable}": "UN"
        },
        "Retry": []
      },
      "x": 358.05555725097656,
      "y": 384.99999618530273,
      "id": "8265a130"
    },
    {
      "type": "node",
      "size": "110*48",
      "shape": "flow-rect",
      "color": "#1890FF",
      "label": "雇员业务",
      "stateId": "EmpServiceTask",
      "stateType": "ServiceTask",
      "stateProps": {
        "ServiceName": "empSaga",
        "ServiceMethod": "reduce",
        "Input": [
          "$.[businessKey]",
          "$.[emp]"
        ],
        "Output": {
          "empServiceReduceResult": "$.#root"
        },
        "Status": {
          "#root == true": "SU",
          "#root == false": "FA",
          "#Exception{java.lang.Throwable}": "UN"
        },
        "Retry": []
      },
      "x": 576.1666564941406,
      "y": 598.5,
      "id": "25e702f3"
    },
    {
      "type": "node",
      "size": "39*39",
      "shape": "flow-circle",
      "color": "red",
      "label": "雇员异常",
      "stateId": "Catch3",
      "stateType": "Catch",
      "x": 637.0555572509766,
      "y": 599,
      "id": "6da2698d"
    },
    {
      "type": "node",
      "size": "110*48",
      "shape": "flow-capsule",
      "color": "red",
      "label": "雇员补偿触发",
      "stateId": "EmpCompensationTrigger",
      "stateType": "CompensationTrigger",
      "x": 837.0555572509766,
      "y": 599,
      "id": "4896f850"
    },
    {
      "type": "node",
      "size": "80*72",
      "shape": "flow-rhombus",
      "color": "#13C2C2",
      "label": "雇员判断",
      "stateId": "Choice2",
      "stateType": "Choice",
      "x": 576.0555572509766,
      "y": 697,
      "id": "38e334a1"
    },
    {
      "type": "node",
      "size": "110*48",
      "shape": "flow-capsule",
      "color": "#722ED1",
      "label": "雇员业务补偿",
      "stateId": "EmpCompensation",
      "stateType": "Compensation",
      "stateProps": {
        "ServiceName": "empSaga",
        "ServiceMethod": "compensateReduce",
        "Input": [
          "$.[businessKey]",
          "$.[emp]"
        ],
        "Output": {
          "empServiceCompensationResult": "$.#root"
        },
        "Status": {
          "#root == true": "SU",
          "#root == false": "FA",
          "#Exception{java.lang.Throwable}": "UN"
        },
        "Retry": []
      },
      "x": 358.05555725097656,
      "y": 598,
      "id": "318a6abf"
    },
    {
      "type": "node",
      "size": "72*72",
      "shape": "flow-circle",
      "color": "#05A465",
      "label": "业务成功",
      "stateId": "SuccessHandle",
      "stateType": "Succeed",
      "x": 357.55555725097656,
      "y": 697,
      "id": "5ae32569"
    }
  ],
  "edges": [
    {
      "source": "4896f850",
      "sourceAnchor": 1,
      "target": "144efa41",
      "targetAnchor": 2,
      "id": "41058926",
      "shape": "flow-polyline-round"
    },
    {
      "source": "dea8dc26",
      "sourceAnchor": 2,
      "target": "15b79f30",
      "targetAnchor": 0,
      "id": "a76175e7",
      "index": 2
    },
    {
      "source": "89b2c29f",
      "sourceAnchor": 1,
      "target": "f483f1ad",
      "targetAnchor": 3,
      "id": "8d5c20b9",
      "shape": "flow-polyline-round",
      "stateProps": {
        "Exceptions": [
          "java.lang.Throwable"
        ]
      }
    },
    {
      "source": "f483f1ad",
      "sourceAnchor": 1,
      "target": "144efa41",
      "targetAnchor": 0,
      "id": "31c116f0",
      "shape": "flow-polyline-round",
      "label": ""
    },
    {
      "source": "fbf4f55f",
      "sourceAnchor": 1,
      "target": "f483f1ad",
      "targetAnchor": 2,
      "id": "46147cf0",
      "shape": "flow-polyline-round",
      "stateProps": {
        "Expression": "[deptServiceReduceResult] == false",
        "Next": "DeptCompensationTrigger"
      },
      "label": ""
    },
    {
      "source": "15b79f30",
      "sourceAnchor": 2,
      "target": "fbf4f55f",
      "targetAnchor": 0,
      "id": "c4db2c15",
      "shape": "flow-polyline-round"
    },
    {
      "source": "8265a130",
      "sourceAnchor": 1,
      "target": "15b79f30",
      "targetAnchor": 3,
      "id": "4075ca26",
      "shape": "flow-polyline-round"
    },
    {
      "source": "fbf4f55f",
      "sourceAnchor": 2,
      "target": "25e702f3",
      "targetAnchor": 0,
      "id": "f56da4ba",
      "shape": "flow-polyline-round",
      "stateProps": {
        "Expression": "[deptServiceReduceResult] == true",
        "Next": "EmpServiceTask"
      },
      "label": ""
    },
    {
      "source": "6da2698d",
      "sourceAnchor": 1,
      "target": "4896f850",
      "targetAnchor": 3,
      "id": "20cb7eff",
      "shape": "flow-polyline-round",
      "stateProps": {
        "Exceptions": [
          "java.lang.Throwable"
        ]
      }
    },
    {
      "source": "318a6abf",
      "sourceAnchor": 1,
      "target": "25e702f3",
      "targetAnchor": 3,
      "id": "0c5a7f0e",
      "shape": "flow-polyline-round"
    },
    {
      "source": "25e702f3",
      "sourceAnchor": 2,
      "target": "38e334a1",
      "targetAnchor": 0,
      "id": "1356332a",
      "shape": "flow-polyline-round"
    },
    {
      "source": "38e334a1",
      "sourceAnchor": 1,
      "target": "4896f850",
      "targetAnchor": 2,
      "id": "f7377441",
      "shape": "flow-polyline-round",
      "stateProps": {
        "Expression": "[empServiceReduceResult]==false",
        "Next": "EmpCompensationTrigger"
      },
      "label": ""
    },
    {
      "source": "38e334a1",
      "sourceAnchor": 3,
      "target": "5ae32569",
      "targetAnchor": 1,
      "id": "c113bddd",
      "shape": "flow-polyline-round",
      "stateProps": {
        "Expression": "[empServiceReduceResult]==true",
        "Next": "SuccessHandle"
      },
      "label": ""
    }
  ]
}

13、

DROP DATABASE IF EXISTS yootk80;
CREATE DATABASE yootk80 CHARACTER SET UTF8;
USE yootk80;
create table seata_state_machine_def(
    id               varchar(32)  not null comment 'id',
    name             varchar(128) not null comment 'name',
    tenant_id        varchar(32)  not null comment 'tenant id',
    app_name         varchar(32)  not null comment 'application name',
    type             varchar(20) comment 'state language type',
    comment_         varchar(255) comment 'comment',
    ver              varchar(16)  not null comment 'version',
    gmt_create       timestamp    not null comment 'create time',
    status           varchar(2)   not null comment 'status(AC:active|IN:inactive)',
    content          text comment 'content',
    recover_strategy varchar(16) comment 'transaction recover strategy(compensate|retry)',
    primary key (id)
);
create table seata_state_machine_inst(
    id                  varchar(128) not null comment 'id',
    machine_id          varchar(32) not null comment 'state machine definition id',
    tenant_id           varchar(32) not null comment 'tenant id',
    parent_id           varchar(128) comment 'parent id',
    gmt_started         timestamp   not null comment 'start time',
    business_key        varchar(48) comment 'business key',
    start_params        text comment 'start parameters',
    gmt_end             timestamp comment 'end time',
    excep               blob comment 'exception',
    end_params          text comment 'end parameters',
    status              varchar(2) comment 'status(SU succeed|FA failed|UN unknown|SK skipped|RU running)',
    compensation_status varchar(2) comment 'compensation status(SU succeed|FA failed|UN unknown|SK skipped|RU running)',
    is_running          tinyint(1) comment 'is running(0 no|1 yes)',
    gmt_updated         timestamp   not null,
    primary key (id),
    unique key unikey_buz_tenant (business_key, tenant_id)
);
create table seata_state_inst(
    id                       varchar(48)  not null comment 'id',
    machine_inst_id          varchar(128)  not null comment 'state machine instance id',
    name                     varchar(128) not null comment 'state name',
    type                     varchar(20) comment 'state type',
    service_name             varchar(128) comment 'service name',
    service_method           varchar(128) comment 'method name',
    service_type             varchar(16) comment 'service type',
    business_key             varchar(48) comment 'business key',
    state_id_compensated_for varchar(50) comment 'state compensated for',
    state_id_retried_for     varchar(50) comment 'state retried for',
    gmt_started              timestamp    not null comment 'start time',
    is_for_update            tinyint(1) comment 'is service for update',
    input_params             text comment 'input parameters',
    output_params            text comment 'output parameters',
    status                   varchar(2)   not null comment 'status(SU succeed|FA failed|UN unknown|SK skipped|RU running)',
    excep                    text comment 'exception',
    gmt_end                  timestamp comment 'end time',
    gmt_updated         timestamp   not null,
    primary key (id, machine_inst_id)
);


14、
project(":consumer-springboot-80") { // 消费端模块
    dependencies {
        implementation(libraries.'spring-cloud-starter-alibaba-seata') {
            exclude group: 'io.seata', module: 'seata-spring-boot-starter'
        }
        implementation(libraries.'seata-spring-boot-starter')
        implementation(libraries.'mysql-connector-java')
        implementation(libraries.'druid')
        implementation(libraries.'spring-boot-admin-starter-client')
        implementation('org.springframework.boot:spring-boot-starter-actuator')
        implementation(project(":common-api")) // 导入公共的子模块
        implementation('com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery') {
            exclude group: 'com.alibaba.nacos', module: 'nacos-client' // 移除旧版本的Nacos依赖
        }
        implementation(libraries.'nacos-client') // 引入与当前的Nacos匹配的依赖库
        implementation(libraries.'httpclient') // 引入httpclient组件
        implementation(libraries.'feign-httpclient') // 引入feign-httpclient组件
    }
}

15、
spring:
  boot:
    admin:
      client:
        username: muyan
        password: yootk
        url: http://microcloud-admin:8000/
  main:
    allow-bean-definition-overriding: true
  application: # 配置应用信息
    name: consumer # 是微服务的名称
  cloud: # Cloud配置
    nacos: # Nacos注册中心配置
      discovery: # 发现服务
        server-addr: nacos-server:8848 # Nacos服务地址
        namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间ID
        group: MICROCLOUD_GROUP # 一般建议大写
        cluster-name: MuyanYootk # 配置集群名称
        username: muyan # 用户名
        password: yootk # 密码
        register-enabled: false # 消费端不注册
        metadata:
          version: 2.0 # 版本编号匹配了
  datasource: # 数据源配置
    type: com.alibaba.druid.pool.DruidDataSource    # 数据源类型
    driver-class-name: com.mysql.cj.jdbc.Driver     # 驱动程序类
    url: jdbc:mysql://localhost:3306/yootk80          # 连接地址
    username: root                                  # 用户名
    password: mysqladmin                            # 连接密码
    druid: # druid相关配置
      initial-size: 5                               # 初始化连接池大小
      min-idle: 10                                  # 最小维持连接池大小
      max-active: 50                                # 最大支持连接池大小
      max-wait: 60000                               # 最大等待时间
      time-between-eviction-runs-millis: 60000      # 关闭空闲连接间隔
      min-evictable-idle-time-millis: 30000         # 连接最小生存时间
      validation-query: SELECT 1 FROM dual          # 状态检测
      test-while-idle: true # 空闲时检测连接是否有效
      test-on-borrow: false # 申请时检测连接是否有效
      test-on-return: false # 归还时检测连接是否有效
      pool-prepared-statements: false # PSCache缓存
      max-pool-prepared-statement-per-connection-size: 20 # 配置PS缓存
      filters: stat, wall, slf4j # 开启过滤
      stat-view-servlet: # 监控界面配置
        enabled: true # 启用druid监控界面
        allow: 127.0.0.1      # 访问白名单
        login-username: muyan # 用户名
        login-password: yootk # 密码
        reset-enable: true # 允许重置
        url-pattern: /druid/* # 访问路径
      web-stat-filter:
        enabled: true # 启动URI监控
        url-pattern: /* # 跟踪全部服务
        exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*" # 跟踪排除
      filter:
        slf4j: # 日志
          enabled: true # 启用SLF4j监控
          data-source-log-enabled: true # 启用数据库日志
          statement-executable-sql-log-enable: true # 执行日志
          result-set-log-enabled: true # ResultSet日志启用
        stat: # SQL监控
          merge-sql: true # 合并统计
          log-slow-sql: true # 慢执行记录
          slow-sql-millis: 1 # 慢SQL执行时间
        wall: # SQL防火墙
          enabled: true   # SQL防火墙
          config: # 防火墙规则
            multi-statement-allow: true # 允许执行批量SQL
            delete-allow: false # 禁止执行删除语句
      aop-patterns: "com.yootk.consumer.action.*" # Spring监控


16、

package com.yootk.consumer.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class DruidConfig {
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druid() {
        return new DruidDataSource();
    }
}


17、
package com.yootk.consumer.config;

import io.seata.saga.engine.config.DbStateMachineConfig;
import io.seata.saga.engine.impl.ProcessCtrlStateMachineEngine;
import io.seata.saga.rm.StateMachineEngineHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.sql.DataSource;
import java.util.concurrent.ThreadPoolExecutor;

@Configuration
public class StateMachineEngineConfig { // 状态机引擎类
    @Autowired
    private DataSource dataSource;
    @Bean
    public ThreadPoolExecutor getThreadPoolExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 线程池定义
        executor.setCorePoolSize(8); // 设置一个核心线程数
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(989999); // 延迟队列
        executor.setThreadNamePrefix("SAGA_ASYNC_EXEC_"); // 线程前缀
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor.getThreadPoolExecutor();
    }
    @Bean
    public DbStateMachineConfig dbStateMachineConfig() {    // 数据库状态机配置
        DbStateMachineConfig stateMachineConfig = new DbStateMachineConfig();
        stateMachineConfig.setDataSource(this.dataSource); // 数据源绑定
        Resource resource = new ClassPathResource("saga/company-hr-add.json");
        stateMachineConfig.setResources(new Resource[] {resource}); // 设置了状态机的配置文件
        stateMachineConfig.setEnableAsync(true);
        stateMachineConfig.setThreadPoolExecutor(getThreadPoolExecutor());
        return stateMachineConfig;
    }
    @Bean
    public ProcessCtrlStateMachineEngine stateMachineEngine() {
        ProcessCtrlStateMachineEngine processCtrlStateMachineEngine = new ProcessCtrlStateMachineEngine();
        processCtrlStateMachineEngine.setStateMachineConfig(dbStateMachineConfig()); // 读取配置
        return processCtrlStateMachineEngine;
    }
    @Bean
    public StateMachineEngineHolder stateMachineEngineHolder() {
        StateMachineEngineHolder engineHolder = new StateMachineEngineHolder();
        engineHolder.setStateMachineEngine(stateMachineEngine());
        return engineHolder;
    }
}


18、

package com.yootk.consumer.saga;

import com.yootk.common.dto.DeptDTO;

public interface IDeptSaga {
    public boolean reduce(String bussinessKey, DeptDTO dept);
    public boolean compensateReduce(String bussinessKey, DeptDTO dept);
}


19、
package com.yootk.consumer.saga.impl;

import com.yootk.common.dto.DeptDTO;
import com.yootk.consumer.saga.IDeptSaga;
import com.yootk.service.IDeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("deptSaga")
@Slf4j
public class DeptSagaImpl implements IDeptSaga {
    @Autowired
    private IDeptService deptService;
    @Override
    public boolean reduce(String bussinessKey, DeptDTO dept) {
        log.info("【部门业务处理】业务KEY:{}、部门信息:{}", bussinessKey, dept);
        if (dept.getDname() == null || "".equals(dept.getDname())) {
            throw new RuntimeException("部门名称不允许为空。");
        }
        try {
            return this.deptService.add(dept);
        } catch (Exception e) {
            return false;
        }
    }
    @Override
    public boolean compensateReduce(String bussinessKey, DeptDTO dept) {
        log.info("【部门业务补偿】业务KEY:{}、部门信息:{}", bussinessKey, dept);
        return false;
    }
}


20、

package com.yootk.consumer.saga;

import com.yootk.common.dto.EmpDTO;

public interface IEmpSaga {
    public boolean reduce(String bussinessKey, EmpDTO emp);
    public boolean compensateReduce(String bussinessKey, EmpDTO emp);
}


21、
package com.yootk.consumer.saga.impl;

import com.yootk.common.dto.DeptDTO;
import com.yootk.common.dto.EmpDTO;
import com.yootk.consumer.saga.IEmpSaga;
import com.yootk.service.IDeptService;
import com.yootk.service.IEmpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("empSaga")
@Slf4j
public class EmpSagaImpl implements IEmpSaga {
    @Autowired
    private IEmpService empService;
    @Override
    public boolean reduce(String bussinessKey, EmpDTO emp) {
        log.info("【雇员业务处理】业务KEY:{}、雇员信息:{}", bussinessKey, emp);
        try {
            return this.empService.add(emp);
        } catch (Exception e) {
            return false;
        }
    }
    @Override
    public boolean compensateReduce(String bussinessKey, EmpDTO emp) {
        log.info("【雇员业务补偿】业务KEY:{}、雇员信息:{}", bussinessKey, emp);
        // 本处不再实现具体的业务补偿微服务调用处理了,整个处理的时候都是一个输出
        return false;
    }
}


22、
package com.yootk.consumer.action;

import com.yootk.common.dto.DeptDTO;
import com.yootk.common.dto.EmpDTO;
import io.seata.saga.engine.StateMachineEngine;
import io.seata.saga.statelang.domain.ExecutionStatus;
import io.seata.saga.statelang.domain.StateMachineInstance;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/consumer/company/*")
@Slf4j
public class CompanyConsumerAction {
    @Autowired
    private StateMachineEngine stateMachineEngine; // 状态机引擎

    @GetMapping("add")
    @GlobalTransactional // 全局事务控制
    public Object add(DeptDTO dept, EmpDTO emp) {
        Map<String, Object> startParams = new HashMap<>(); // 保存最终的结果
        String businessKey = String.valueOf(System.currentTimeMillis()); // 模拟业务KEY
        startParams.put("businessKey", businessKey); // 保存参数
        startParams.put("dept", dept); // 保存参数
        startParams.put("emp", emp); // 保存参数
        StateMachineInstance instance = this.stateMachineEngine.startWithBusinessKey("CompanyService", null, businessKey, startParams);
        if (ExecutionStatus.SU.equals(instance.getStatus())) {  // 操作成功
            log.info("人事数据创建成功,XID = {}", instance.getId());
            return true;
        } else {
            log.info("人事数据创建失败,XID = {}", instance.getId());
            return false;
        }
    }
}

23、
http://consumer-springboot-80/consumer/company/add?empno=20&ename=小李&salary=800.0&deptno=1&deptno=88&dname=TCC测试部 - 3&loc=洛阳


s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031904] Begin process the state instance in the saga branch.
c.yootk.consumer.saga.impl.DeptSagaImpl  : 【部门业务处理】业务KEY:1636880246475、部门信息:DeptDTO(deptno=1, dname=TCC测试部 - 3, loc=洛阳)
com.yootk.service.IDeptService           : [IDeptService#add] ---> POST http://microcloud.gateway/provider/dept/add HTTP/1.1
com.yootk.service.IDeptService           : [IDeptService#add] Accept-Encoding: gzip
com.yootk.service.IDeptService           : [IDeptService#add] Accept-Encoding: deflate
com.yootk.service.IDeptService           : [IDeptService#add] Content-Length: 54
com.yootk.service.IDeptService           : [IDeptService#add] Content-Type: application/json
com.yootk.service.IDeptService           : [IDeptService#add] serviceName: pc
com.yootk.service.IDeptService           : [IDeptService#add] yootk-token: eyJhdXRob3IiOiLmnY7lhbTljY4iLCJtb2R1bGUiOiJ0b2tlbi5wcm92aWRlciIsImFsZyI6IkhTMjU2In0.eyJtc2ciOiLkuJbnlYzkuIrniIblj6_niLHnmoTogIHluIgg4oCU4oCUIOeIhuWPr-eIseeahOWwj-adjuiAgeW4iCIsInN1YiI6IntcInJvbGVzXCI6W1wibWVtYmVyXCIsXCJlbXBcIixcImRlcHRcIl0sXCJhY3Rpb25zXCI6W1wiZW1wOmxpc3RcIixcImRlcHQ6ZWRpdFwiLFwiZGVwdDpsaXN0XCIsXCJlbXA6ZWRpdFwiLFwibWVtYmVyOmFkZFwiLFwiZGVwdDphZGRcIixcImVtcDphZGRcIixcIm1lbWJlcjplZGl0XCIsXCJkZXB0OmRlbGV0ZVwiLFwibWVtYmVyOmRlbGV0ZVwiLFwibWVtYmVyOmxpc3RcIixcImVtcDpkZWxldGVcIl19Iiwic2l0ZSI6Ind3dy55b290ay5jb20iLCJpc3MiOiJNdXlhbllvb3RrIiwiZXhwIjoxNjM2OTgwMjQxLCJpYXQiOjE2MzY4ODAyNDEsIm5pY2UiOiJHb29kIEdvb2QgR29vZCIsImp0aSI6ImFkbWluIn0.I7_ltF6uJPkVKYQz_2ZlupPF132KioPTq5LlkULiMVQ
com.yootk.service.IDeptService           : [IDeptService#add]
com.yootk.service.IDeptService           : [IDeptService#add] {"deptno":1,"dname":"TCC测试部 - 3","loc":"洛阳"}
com.yootk.service.IDeptService           : [IDeptService#add] ---> END HTTP (54-byte body)
com.yootk.service.IDeptService           : [IDeptService#add] <--- HTTP/1.1 200 OK (110ms)
com.yootk.service.IDeptService           : [IDeptService#add] cache-control: no-cache, no-store, max-age=0, must-revalidate
com.yootk.service.IDeptService           : [IDeptService#add] content-type: application/json
com.yootk.service.IDeptService           : [IDeptService#add] date: Sun, 14 Nov 2021 08:57:26 GMT
com.yootk.service.IDeptService           : [IDeptService#add] expires: 0
com.yootk.service.IDeptService           : [IDeptService#add] pragma: no-cache
com.yootk.service.IDeptService           : [IDeptService#add] transfer-encoding: chunked
com.yootk.service.IDeptService           : [IDeptService#add] x-content-type-options: nosniff
com.yootk.service.IDeptService           : [IDeptService#add] x-frame-options: DENY
com.yootk.service.IDeptService           : [IDeptService#add] x-xss-protection: 1; mode=block
com.yootk.service.IDeptService           : [IDeptService#add]
com.yootk.service.IDeptService           : [IDeptService#add] true
com.yootk.service.IDeptService           : [IDeptService#add] <--- END HTTP (4-byte body)
.s.s.e.p.i.ServiceTaskHandlerInterceptor : State[DeptServiceTask] finish with status[SU]
s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031904] Finish process the state instance in the saga branch.
s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031904] Begin process the state instance in the saga branch.
c.yootk.consumer.saga.impl.EmpSagaImpl   : 【雇员业务处理】业务KEY:1636880246475、雇员信息:EmpDTO(empno=20, ename=小李, salary=800.0, deptno=1)
.s.s.e.p.i.ServiceTaskHandlerInterceptor : State[EmpServiceTask] finish with status[SU]
s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031904] Finish process the state instance in the saga branch.
i.s.s.e.s.db.DbAndReportTcStateLogStore  : StateMachineInstance[192.168.190.191:8091:6143108224087031904] is recovery by server, skip recordStateMachineFinished.
i.s.s.p.handler.DefaultRouterHandler     : route instruction is null, process end
c.y.c.action.CompanyConsumerAction       : 人事数据创建成功,XID = 192.168.190.191:8091:6143108224087031904
i.seata.tm.api.DefaultGlobalTransaction  : [192.168.190.191:8091:6143108224087031904] commit status: Committed




i.seata.tm.api.DefaultGlobalTransaction  : Begin new global transaction [192.168.190.191:8091:6143108224087031909]
c.a.druid.pool.DruidAbstractDataSource   : discard long time none received connection. , jdbcUrl : jdbc:mysql://localhost:3306/yootk80, version : 1.2.5, lastPacketReceivedIdleMillis : 113639
s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031909] Begin process the state instance in the saga branch.
c.yootk.consumer.saga.impl.DeptSagaImpl  : 【部门业务处理】业务KEY:1636880361108、部门信息:DeptDTO(deptno=1, dname=TCC测试部 - 3, loc=洛阳)
com.yootk.service.IDeptService           : [IDeptService#add] ---> POST http://microcloud.gateway/provider/dept/add HTTP/1.1
com.yootk.service.IDeptService           : [IDeptService#add] Accept-Encoding: gzip
com.yootk.service.IDeptService           : [IDeptService#add] Accept-Encoding: deflate
com.yootk.service.IDeptService           : [IDeptService#add] Content-Length: 54
com.yootk.service.IDeptService           : [IDeptService#add] Content-Type: application/json
com.yootk.service.IDeptService           : [IDeptService#add] serviceName: pc
com.yootk.service.IDeptService           : [IDeptService#add] yootk-token: eyJhdXRob3IiOiL...
com.yootk.service.IDeptService           : [IDeptService#add]
com.yootk.service.IDeptService           : [IDeptService#add] {"deptno":1,"dname":"TCC测试部 - 3","loc":"洛阳"}
com.yootk.service.IDeptService           : [IDeptService#add] ---> END HTTP (54-byte body)
com.yootk.service.IDeptService           : [IDeptService#add] <--- HTTP/1.1 200 OK (109ms)
com.yootk.service.IDeptService           : [IDeptService#add] cache-control: no-cache, no-store, max-age=0, must-revalidate
com.yootk.service.IDeptService           : [IDeptService#add] content-type: application/json
com.yootk.service.IDeptService           : [IDeptService#add] date: Sun, 14 Nov 2021 08:59:21 GMT
com.yootk.service.IDeptService           : [IDeptService#add] expires: 0
com.yootk.service.IDeptService           : [IDeptService#add] pragma: no-cache
com.yootk.service.IDeptService           : [IDeptService#add] transfer-encoding: chunked
com.yootk.service.IDeptService           : [IDeptService#add] x-content-type-options: nosniff
com.yootk.service.IDeptService           : [IDeptService#add] x-frame-options: DENY
com.yootk.service.IDeptService           : [IDeptService#add] x-xss-protection: 1; mode=block
com.yootk.service.IDeptService           : [IDeptService#add]
com.yootk.service.IDeptService           : [IDeptService#add] true
com.yootk.service.IDeptService           : [IDeptService#add] <--- END HTTP (4-byte body)
.s.s.e.p.i.ServiceTaskHandlerInterceptor : State[DeptServiceTask] finish with status[SU]
s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031909] Finish process the state instance in the saga branch.
s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031909] Begin process the state instance in the saga branch.
c.yootk.consumer.saga.impl.EmpSagaImpl   : 【雇员业务处理】业务KEY:1636880361108、雇员信息:EmpDTO(empno=20, ename=小李, salary=800.0, deptno=1)
feign.FeignException$InternalServerError: [500 Internal Server Error] during [POST] to [http://microcloud.gateway/provider/emp/add] [IEmpService#add(EmpDTO)]: [{"timestamp":"2021-11-14T08:59:21.742+0000","status":500,"error":"Internal Server Error","message":"\r\n### Error updating database.  Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicat... (11108 bytes)]
	at feign.FeignException.serverErrorStatus(FeignException.java:231)
	at feign.FeignException.errorStatus(FeignException.java:180)
	at feign.FeignException.errorStatus(FeignException.java:169)
	at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:92)
	at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:156)
	at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:80)
	at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100)
	at com.sun.proxy.$Proxy126.add(Unknown Source)
	at com.yootk.consumer.saga.impl.EmpSagaImpl.reduce(EmpSagaImpl.java:21)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at io.seata.saga.engine.invoker.impl.SpringBeanServiceInvoker.invokeMethod(SpringBeanServiceInvoker.java:278)
	at io.seata.saga.engine.invoker.impl.SpringBeanServiceInvoker.doInvoke(SpringBeanServiceInvoker.java:141)
	at io.seata.saga.engine.invoker.impl.SpringBeanServiceInvoker.invoke(SpringBeanServiceInvoker.java:90)
	at io.seata.saga.engine.pcext.handlers.ServiceTaskStateHandler.process(ServiceTaskStateHandler.java:102)
	at io.seata.saga.engine.pcext.StateMachineProcessHandler.process(StateMachineProcessHandler.java:71)
	at io.seata.saga.proctrl.process.impl.CustomizeBusinessProcessor.process(CustomizeBusinessProcessor.java:69)
	at io.seata.saga.proctrl.impl.ProcessControllerImpl.process(ProcessControllerImpl.java:43)
	at io.seata.saga.proctrl.eventing.impl.ProcessCtrlEventConsumer.process(ProcessCtrlEventConsumer.java:35)
	at io.seata.saga.proctrl.eventing.impl.ProcessCtrlEventConsumer.process(ProcessCtrlEventConsumer.java:28)
	at io.seata.saga.proctrl.eventing.impl.DirectEventBus.offer(DirectEventBus.java:69)
	at io.seata.saga.proctrl.eventing.impl.DirectEventBus.offer(DirectEventBus.java:33)
	at io.seata.saga.proctrl.eventing.impl.ProcessCtrlEventPublisher.publish(ProcessCtrlEventPublisher.java:34)
	at io.seata.saga.engine.impl.ProcessCtrlStateMachineEngine.startInternal(ProcessCtrlStateMachineEngine.java:155)
	at io.seata.saga.engine.impl.ProcessCtrlStateMachineEngine.startWithBusinessKey(ProcessCtrlStateMachineEngine.java:91)
	at com.yootk.consumer.action.CompanyConsumerAction.add(CompanyConsumerAction.java:33)
	at com.yootk.consumer.action.CompanyConsumerAction$$FastClassBySpringCGLIB$$e5c5a4be.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
	at io.seata.spring.annotation.GlobalTransactionalInterceptor$2.execute(GlobalTransactionalInterceptor.java:184)
	at io.seata.tm.api.TransactionalTemplate.execute(TransactionalTemplate.java:127)
	at io.seata.spring.annotation.GlobalTransactionalInterceptor.handleGlobalTransaction(GlobalTransactionalInterceptor.java:181)
	at io.seata.spring.annotation.GlobalTransactionalInterceptor.invoke(GlobalTransactionalInterceptor.java:150)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
	at com.yootk.consumer.action.CompanyConsumerAction$$EnhancerBySpringCGLIB$$d0a5a587.add(<generated>)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1639)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:834)
.s.s.e.p.i.ServiceTaskHandlerInterceptor : State[EmpServiceTask] finish with status[FA]
s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031909] Finish process the state instance in the saga branch.
i.s.s.e.s.db.DbAndReportTcStateLogStore  : StateMachineInstance[192.168.190.191:8091:6143108224087031909] is recovery by server, skip recordStateMachineFinished.
i.s.s.e.pcext.routers.TaskStateRouter    : StateInstruction is ended, Stop the StateMachine executing. StateMachine[CompanyService] Current State[EmpCompensationTrigger]
i.s.s.p.handler.DefaultRouterHandler     : route instruction is null, process end
c.y.c.action.CompanyConsumerAction       : 人事数据创建失败,XID = 192.168.190.191:8091:6143108224087031909
i.seata.tm.api.DefaultGlobalTransaction  : [192.168.190.191:8091:6143108224087031909] commit status: Committed



c.yootk.consumer.saga.impl.DeptSagaImpl  : 【部门业务处理】业务KEY:1636882180037、部门信息:DeptDTO(deptno=1, dname=Saga部门  - 1, loc=洛阳)
com.yootk.service.IDeptService           : [IDeptService#add] ---> POST http://microcloud.gateway/provider/dept/add HTTP/1.1
com.yootk.service.IDeptService           : [IDeptService#add] Accept-Encoding: gzip
com.yootk.service.IDeptService           : [IDeptService#add] Accept-Encoding: deflate
com.yootk.service.IDeptService           : [IDeptService#add] Content-Length: 53
com.yootk.service.IDeptService           : [IDeptService#add] Content-Type: application/json
com.yootk.service.IDeptService           : [IDeptService#add] serviceName: pc
com.yootk.service.IDeptService           : [IDeptService#add] yootk-token: eyJhdXRob3IiOiLmnY7lhbTljY4iLCJtb2R1bGUiOiJ0b2tlbi5wcm92aWRlciIsImFsZyI6IkhTMjU2In0.eyJtc2ciOiLkuJbnlYzkuIrniIblj6_niLHnmoTogIHluIgg4oCU4oCUIOeIhuWPr-eIseeahOWwj-adjuiAgeW4iCIsInN1YiI6IntcInJvbGVzXCI6W1wibWVtYmVyXCIsXCJlbXBcIixcImRlcHRcIl0sXCJhY3Rpb25zXCI6W1wiZW1wOmxpc3RcIixcImRlcHQ6ZWRpdFwiLFwiZGVwdDpsaXN0XCIsXCJlbXA6ZWRpdFwiLFwibWVtYmVyOmFkZFwiLFwiZGVwdDphZGRcIixcImVtcDphZGRcIixcIm1lbWJlcjplZGl0XCIsXCJkZXB0OmRlbGV0ZVwiLFwibWVtYmVyOmRlbGV0ZVwiLFwibWVtYmVyOmxpc3RcIixcImVtcDpkZWxldGVcIl19Iiwic2l0ZSI6Ind3dy55b290ay5jb20iLCJpc3MiOiJNdXlhbllvb3RrIiwiZXhwIjoxNjM2OTgyMTUwLCJpYXQiOjE2MzY4ODIxNTAsIm5pY2UiOiJHb29kIEdvb2QgR29vZCIsImp0aSI6ImFkbWluIn0.5MMR94PKHl7myGHzuesreBEfKyYRQmzFUflMIPXMpEE
com.yootk.service.IDeptService           : [IDeptService#add]
com.yootk.service.IDeptService           : [IDeptService#add] {"deptno":1,"dname":"Saga部门  - 1","loc":"洛阳"}
com.yootk.service.IDeptService           : [IDeptService#add] ---> END HTTP (53-byte body)
com.yootk.service.IDeptService           : [IDeptService#add] <--- HTTP/1.1 200 OK (101ms)
com.yootk.service.IDeptService           : [IDeptService#add] cache-control: no-cache, no-store, max-age=0, must-revalidate
com.yootk.service.IDeptService           : [IDeptService#add] content-type: application/json
com.yootk.service.IDeptService           : [IDeptService#add] date: Sun, 14 Nov 2021 09:29:40 GMT
com.yootk.service.IDeptService           : [IDeptService#add] expires: 0
com.yootk.service.IDeptService           : [IDeptService#add] pragma: no-cache
com.yootk.service.IDeptService           : [IDeptService#add] transfer-encoding: chunked
com.yootk.service.IDeptService           : [IDeptService#add] x-content-type-options: nosniff
com.yootk.service.IDeptService           : [IDeptService#add] x-frame-options: DENY
com.yootk.service.IDeptService           : [IDeptService#add] x-xss-protection: 1; mode=block
com.yootk.service.IDeptService           : [IDeptService#add]
com.yootk.service.IDeptService           : [IDeptService#add] true
com.yootk.service.IDeptService           : [IDeptService#add] <--- END HTTP (4-byte body)
.s.s.e.p.i.ServiceTaskHandlerInterceptor : State[DeptServiceTask] finish with status[SU]
s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031955] Finish process the state instance in the saga branch.
s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031955] Begin process the state instance in the saga branch.
c.yootk.consumer.saga.impl.EmpSagaImpl   : 【雇员业务处理】业务KEY:1636882180037、雇员信息:EmpDTO(empno=20, ename=小李, salary=800.0, deptno=1)
feign.FeignException$InternalServerError: [500 Internal Server Error] during [POST] to [http://microcloud.gateway/provider/emp/add] [IEmpService#add(EmpDTO)]: [{"timestamp":"2021-11-14T09:29:40.915+0000","status":500,"error":"Internal Server Error","message":"\r\n### Error updating database.  Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicat... (11108 bytes)]
.s.s.e.p.i.ServiceTaskHandlerInterceptor : State[EmpServiceTask] finish with status[FA]
s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031955] Finish process the state instance in the saga branch.
s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031955] Begin process the state instance in the saga branch.
c.yootk.consumer.saga.impl.DeptSagaImpl  : 【部门业务补偿】业务KEY:1636882180037、部门信息:DeptDTO(deptno=1, dname=Saga部门  - 1, loc=洛阳)
.s.s.e.p.i.ServiceTaskHandlerInterceptor : State[deptCompensation] finish with status[FA]
s.s.e.p.i.InSagaBranchHandlerInterceptor : [192.168.190.191:8091:6143108224087031955] Finish process the state instance in the saga branch.
i.s.s.e.s.db.DbAndReportTcStateLogStore  : StateMachineInstance[192.168.190.191:8091:6143108224087031955] is recovery by server, skip recordStateMachineFinished.
i.s.s.p.handler.DefaultRouterHandler     : route instruction is null, process end
c.y.c.action.CompanyConsumerAction       : 人事数据创建失败,XID = 192.168.190.191:8091:6143108224087031955
i.seata.tm.api.DefaultGlobalTransaction  : [192.168.190.191:8091:6143108224087031955] commit status: Committed


demo


上次编辑于: