• Springcloud2021+Nacos2.2+Dubbo3+Seata1.6实现分布式事务


    示例代码地址:https://gitee.com/gtnotgod/Springcloud-alibaba.git
    更详细参考Gitee完整的项目:https://gitee.com/gtnotgod/Springcloud-alibaba.git

    官网下载Nacos

    https://nacos.io/zh-cn/index.html
    image

    压缩包解压:

    image

    配置Nacos:**/nacos/conf/application.properties

    #*************** Spring Boot Related Configurations ***************#
    ### Default web context path:
    server.servlet.contextPath=/nacos
    ### Include message field
    server.error.include-message=ALWAYS
    ### Default web server port:
    server.port=8848
    ### Metrics for elastic search
    management.metrics.export.elastic.enabled=false
    #management.metrics.export.elastic.host=http://localhost:9200
    #*************** Access Log Related Configurations ***************#
    ### If turn on the access log:
    server.tomcat.accesslog.enabled=true
    ### The access log pattern:
    server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i
    ### The directory of access log:
    server.tomcat.basedir=file:.
    #*************** Access Control Related Configurations ***************#
    ### If enable spring security, this option is deprecated in 1.2.0:
    #spring.security.enabled=false
    ### The ignore urls of auth
    nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
    ### The auth system to use, currently only 'nacos' and 'ldap' is supported:
    nacos.core.auth.system.type=nacos
    ### If turn on auth system: ### 开启鉴权
    nacos.core.auth.enabled=true
    ### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
    nacos.core.auth.caching.enabled=true
    ### 关闭使用user-agent判断服务端请求并放行鉴权的功能
    nacos.core.auth.enable.userAgentAuthWhite=false
    ### Since 1.4.1, worked when nacos.core.auth.enabled=true and nacos.core.auth.enable.userAgentAuthWhite=false.
    ### The two properties is the white list for auth and used by identity the request from other server.
    nacos.core.auth.server.identity.key=nacos
    nacos.core.auth.server.identity.value=nacos
    ### The token expiration in seconds:
    nacos.core.auth.plugin.nacos.token.cache.enable=false
    nacos.core.auth.plugin.nacos.token.expire.seconds=18000
    ### The default token (Base64 String):
    nacos.core.auth.default.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
    ### 2.1.0 版本后
    nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
    nacos.istio.mcp.server.enabled=false
    

    启动Nacos:进入目录/nacos/bin

    startup.cmd -m standalone

    启动完成,
    image

    访问: http://localhost:8848/nacos

    image

    访问:账号密码 nacos nacos

    image

    官网下载Seata

    https://seata.io/zh-cn/index.html

    image

    本地解压
    image

    初始化数据库:进入seata\script\server\db

    image

    配置Naco配置中心和Nacos注册中心,Mysql数据库

    seata\conf\application.yml

    
    server:
      port: 7091
    
    spring:
      application:
        name: seata-server
    
    logging:
      config: classpath:logback-spring.xml
      file:
        path: ${user.home}/logs/seata
      extend:
        logstash-appender:
          destination: 127.0.0.1:4560
        kafka-appender:
          bootstrap-servers: 127.0.0.1:9092
          topic: logback_to_logstash
    
    console:
      user:
        username: seata
        password: seata
    
    seata:
      service:
        vgroup-mapping:
          my-seata-group: default
      config:
        type: nacos
        nacos:
          server-addr: 127.0.0.1:8848
          group : "SEATA_GROUP"
          namespace: "70180ace-e644-4a10-b590-e6a6003b1bbe"
          username: "nacos"
          password: "nacos"
          data-id: seataServer.properties
      registry:
        type: nacos
        nacos:
          application: seata-server
          server-addr: 127.0.0.1:8848
          group : "SEATA_GROUP"
          namespace: "70180ace-e644-4a10-b590-e6a6003b1bbe"
          username: "nacos"
          password: "nacos"
      store:
        # support: file 、 db 、 redis
        # 注意数据库版本为5.7.26 , 使用8.0.12时报错Could not retrieve transation read-only status server
        mode: db
        db:
          datasource: druid
          db-type: mysql
          driver-class-name: com.mysql.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/seata1.6.1?rewriteBatchedStatements=true&useUnicode=true
          user: root
          password: root
          min-conn: 5
          max-conn: 100
          global-table: global_table
          branch-table: branch_table
          lock-table: lock_table
          distributed-lock-table: distributed_lock
          query-limit: 100
          max-wait: 5000
    #  server:
    #    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
      security:
        secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
        tokenValidityInMilliseconds: 1800000
        ignore:
          urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login
    

    启动Seata ,双击

    image
    出现这个
    image

    Nacos服务列表

    image
    出现这个
    image

    Nacos控制台配置 tx-service-group

    image
    出现这个
    image

    springcloud项目集成Nacos和Seata

    项目公共依赖:

    公共依赖lombok、web、MySQL、mybatisplus、dynamicDataSource、knife4j、bootstrap、loadbalancer

     <properties>
            <mybatis-plus.version>3.5.1mybatis-plus.version>
            <com.alibaba.druid.version>1.2.11com.alibaba.druid.version>
            <nacos-client.version>2.0.4nacos-client.version>
            <fastJson-version>2.0.18fastJson-version>
        properties>
    
        <dependencies>
            
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
            dependency>
            
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
    
            
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
            dependency>
            <dependency>
                <groupId>com.alibabagroupId>
                <artifactId>druid-spring-boot-starterartifactId>
                <version>${com.alibaba.druid.version}version>
            dependency>
            
            <dependency>
                <groupId>com.baomidougroupId>
                <artifactId>mybatis-plus-generatorartifactId>
                <version>${mybatis-plus.version}version>
            dependency>
            
            <dependency>
                <groupId>com.baomidougroupId>
                <artifactId>mybatis-plus-boot-starterartifactId>
                <version>${mybatisplus.verison}version>
            dependency>
            
            <dependency>
                <groupId>org.apache.velocitygroupId>
                <artifactId>velocity-engine-coreartifactId>
                <version>${velocity.engine.version}version>
            dependency>
            
            <dependency>
                <groupId>com.baomidougroupId>
                <artifactId>dynamic-datasource-spring-boot-starterartifactId>
                <version>${mybatisplus.verison}version>
            dependency>
            
            <dependency>
                <groupId>com.github.xiaoymingroupId>
                <artifactId>knife4j-spring-boot-starterartifactId>
                <version>${knife4j.version}version>
            dependency>
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-bootstrapartifactId>
            dependency>
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-loadbalancerartifactId>
            dependency>
            <dependency>
                <groupId>com.alibaba.fastjson2groupId>
                <artifactId>fastjson2artifactId>
                <version>${fastJson-version}version>
            dependency>
        dependencies>
    

    项目一 AppUserManage :10085

    依赖

     <dependencies>
    
            
            <dependency>
                <groupId>io.seatagroupId>
                <artifactId>seata-allartifactId>
                <version>${seata.version}version>
            dependency>
    
            
            
            <dependency>
                <groupId>io.seatagroupId>
                <artifactId>seata-spring-boot-starterartifactId>
                <version>${seata.version}version>
            dependency>
            
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-seataartifactId>
                <exclusions>
                    <exclusion>
                        <groupId>io.seatagroupId>
                        <artifactId>seata-spring-boot-starterartifactId>
                    exclusion>
                    <exclusion>
                        <groupId>io.seatagroupId>
                        <artifactId>seata-allartifactId>
                    exclusion>
                exclusions>
            dependency>
    
            
            <dependency>
                <groupId>com.gtongroupId>
                <artifactId>common-dependceartifactId>
                <version>0.0.1-SNAPSHOTversion>
            dependency>
            
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
            dependency>
            
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
            dependency>
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starterartifactId>
            dependency>
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-bootstrapartifactId>
                <version>3.1.1version>
            dependency>
    
            
            <dependency>
                <groupId>org.apache.dubbogroupId>
                <artifactId>dubboartifactId>
            dependency>
            
            <dependency>
                <groupId>org.apache.dubbogroupId>
                <artifactId>dubbo-spring-boot-starterartifactId>
            dependency>
            
            <dependency>
                <groupId>org.apache.dubbogroupId>
                <artifactId>dubbo-registry-nacosartifactId>
            dependency>
            
            <dependency>
                <groupId>com.alibaba.nacosgroupId>
                <artifactId>nacos-clientartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintagegroupId>
                        <artifactId>junit-vintage-engineartifactId>
                    exclusion>
                exclusions>
            dependency>
            
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-data-redisartifactId>
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework.bootgroupId>
                        <artifactId>spring-boot-starterartifactId>
                    exclusion>
                    <exclusion>
                        <groupId>org.springframework.bootgroupId>
                        <artifactId>spring-boot-starterartifactId>
                    exclusion>
                exclusions>
            dependency>
            
            <dependency>
                <groupId>org.apache.commonsgroupId>
                <artifactId>commons-pool2artifactId>
            dependency>
        dependencies>
    

    核心配置 bootstrap.yml

    # Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
    # Nacos 配置中心的namespace。需要注意,如果使用 public 的 namcespace ,请不要填写这个值,直接留空即可
    # spring.cloud.nacos.config.namespace=
    spring:
      application:
        #服务自动发现并注册,不需要name
        name: user-manager
      cloud:
        alibaba:
          seata:
            tx-service-group: my-seata-group
        nacos:
          discovery:
            server-addr: ${spring.cloud.nacos.server-addr}  # 设置配置中心服务端地址
            group: AlibabaCloud
            username: nacos
            password: nacos
            namespace: 70180ace-e644-4a10-b590-e6a6003b1bbe
          config:
            username: ${spring.cloud.nacos.discovery.username}    # Nacos认证信息用户名
            password: ${spring.cloud.nacos.discovery.password}     # Nacos认证信息密码
            context-path: /nacos    # Nacos根路径
            enabled: true
            server-addr: ${spring.cloud.nacos.server-addr}
            group: ${spring.cloud.nacos.discovery.group}
            namespace: 70180ace-e644-4a10-b590-e6a6003b1bbe
            file-extension: properties
          server-addr: 127.0.0.1:8848 # 设置配置中心服务端地址
    seata:
      enabled: true
      application-id: ${spring.application.name}
      # 客户端和服务端在同一个事务组; Seata 事务组编号,用于 TC 集群名, 一定要和 config.tx(nacos) 中配置的相同
      tx-service-group: my-seata-group
      # 自动数据源代理
      enable-auto-data-source-proxy: true
      # 数据源代理模式(分布式事务方案)
      data-source-proxy-mode: AT
      # 事务群组,配置项值为TC集群名,需要与服务端保持一致
      service:
        vgroup-mapping:
          my-seata-group: default
      #整合nacos配置中心
      config:
        type: nacos
        nacos:
          server-addr: ${spring.cloud.nacos.server-addr}
          group: SEATA_GROUP
          namespace: 70180ace-e644-4a10-b590-e6a6003b1bbe
          data-id: seataServer.properties
          username: nacos
          password: nacos
      #整合nacos注册中心
      registry:
        type: nacos
        nacos:
          server-addr: ${spring.cloud.nacos.server-addr}
          group: SEATA_GROUP
          namespace: 70180ace-e644-4a10-b590-e6a6003b1bbe
          # 默认TC集群名
          cluster: default
          # 服务名,与服务端中registry.conf配置要一致
          application: seata-server
          username: nacos
          password: nacos
    dubbo:
      # 配置元数据中心
      metadata-report:
        address: nacos://127.0.0.1:8848?username=${dubbo.metadata-report.username}&password=${dubbo.metadata-report.password}
        username: nacos
        password: nacos
        parameters:
          namespace: 70180ace-e644-4a10-b590-e6a6003b1bbe
        retry-times: 30  #重试次数,默认100
        cycle-report: false #关闭定时刷新
      application:
        name: dubbo-consumer
        # 禁用QOS同一台机器可能会有端口冲突现象
        qos-enable: false
        qos-accept-foreign-ip: false
        service-discovery:
          migration: FORCE_APPLICATION # FORCE_APPLICATION,只消费应用级地址,如无地址则报错,单订阅 3.x 地址
      protocol:
        name: dubbo
        port: -1
      scan:
        base-packages: com.gton.router.impl
      cloud:
        subscribed-services: consumer
      registry:
        address: nacos://127.0.0.1:8848?username=${dubbo.metadata-report.username}&password=${dubbo.metadata-report.password}
        parameters:
          namespace: 70180ace-e644-4a10-b590-e6a6003b1bbe
      consumer:
        check: false
    

    启动类

    package com.gton;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    /**
     * @description: APP-Usermanage服务
     * @author: GuoTong
     * @createTime: 2022-09-24 13:48
     * @since JDK 1.8 OR 11
     **/
    @SpringBootApplication
    @EnableDiscoveryClient //服务发现客户端
    public class AppUserManage {
    
        public static void main(String[] args) {
            /**
             * Description:
             * 数据库连接全部使用mybatis-plus安全加密,加密密匙:
             * 在启动参数 (Program arguments)  --mpw.key=4b57e89bac82a797
             */
            try {
                SpringApplication.run(AppUserManage.class, args);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    

    测试接口 包含:Dubbo的RPC调用,Seata分布式事务的测试

    
    /**
     * @description:
     * @author: GuoTong
     * @createTime: 2022-09-24 14:37
     * @since JDK 1.8 OR 11
     **/
    @RestController
    @Api(tags = "测试接口")
    @SwaggerScanClass
    @Slf4j
    public class HelloController {
    
        @Value("${user.name:zhangsan}")
        private String name;
    
        @Value("${user.age:100}")
        private int age;
    
    
        @Autowired
        private GpLoginService gpLoginService;
    
    
        /**
         * Description: Dubbo RPC调用服务方
         *
         * @author: GuoTong
         * @date: 2022-09-24 17:50:08
         * @param null
         * @return:
         */
        @Autowired
        private DubboRPCThirdSysRouterService dubboRPCThirdSysRouterService;
    
    
        @RequestMapping(value = "/hello", method = RequestMethod.GET)
        @ApiOperation(value = "hello", notes = "json格式")
        @ApiResponse(code = 200, message = "返回的是json格式", response = Resp.class)
        public Resp hello() {
            Map data = new HashMap<>();
            data.put("call-UrI", "hello");
            data.put("port", "8089");
            data.put("service-Name", "cloud-nacos");
            data.put("server-type", "nacos");
            data.put("server-addr", "127.0.0.1:8848");
            data.put("swagger-Uri", "doc.html");
            data.put("nacos-properties-name", name);
            data.put("nacos-properties-age", age);
            return Resp.Ok(data);
        }
    
    
        @RequestMapping(value = "/dubbo_get_thirdsysrouter", method = RequestMethod.GET)
        @ApiOperation(value = "usermanager服务调用thirdsysrouter", notes = "json格式")
        @ApiResponse(code = 200, message = "返回的是json格式", response = Resp.class)
        public Resp getThirdSysRouterInDubbo(HttpServletRequest request) {
            String traceId = MDC.get(ContextCommonMsg.TRACE_ID);
            String username = request.getParameter("username");
            if (StringUtils.isEmpty(username)) {
                username = "郭童";
            }
            return dubboRPCThirdSysRouterService.getUserManagerService_Hello(traceId, username);
        }
    
    
        @GlobalTransactional
        @RequestMapping(value = "/dubbo_seata_thirdsysrouter", method = RequestMethod.GET)
        @ApiOperation(value = "usermanager服务调用thirdsysrouter分布式事务", notes = "json格式")
        @ApiResponse(code = 200, message = "返回的是json格式", response = Resp.class)
        public Resp getThirdSysRouterInDubboBySeata(HttpServletRequest request) {
            String traceId = MDC.get(ContextCommonMsg.TRACE_ID);
            String username = request.getParameter("username");
            if (StringUtils.isEmpty(username)) {
                username = "郭童";
            }
            // 插入本地数据库
            GpLogin gpLogin = new GpLogin().
                    setUsername("GlobalTransactional" + username)
                    .setPassword("dubbo_seata_thirdsysrouter")
                    .setWelcomeName("分布式事务" + traceId);
            gpLoginService.save(gpLogin);
            log.info("第一段插入数据库study库成功" + gpLogin.getId());
            Resp resp = dubboRPCThirdSysRouterService.databaseUpdate(gpLogin);
            log.info("分布式事务----结束,第二段插入数据库study02-id={},响应码=" + resp.getCode(), resp.getData());
            int j = 100 / 0;
            return resp;
        }
    }
    
    

    Seata的核心注解: 全局AT的undolog依赖关系型数据库的事务 开启@GlobalTransactional

    Dubbo的核心注解: 调用方:@DubboReference 被调方: @DubboService

    省略。。。。。。。。

    项目二 ThirdSysRouterApp :8099

    配合+依赖和项目一类似,使用不同的数据库和一张表。。。。。。。。。

    项目一的Dubbo调用项目二的方法

    /**
     * @description: 基于dubbo实现远程过程调用
     * @author: GuoTong
     * @createTime: 2022-09-24 17:40
     * @since JDK 1.8 OR 11
     **/
    @Service
    @DubboService
    @Slf4j
    public class DubboRouterService implements RemoteUserManageService {
    
        @Autowired
        private GotoUserManagerService gotoUserManagerService;
    
        @Autowired
        private StudentService studentService;
    
        /**
         * Description: Dubbo的消息提供方  @DubboService
         *
         * @author: GuoTong
         * @date: 2022-09-24 17:42:36
         */
    
        @Override
        public Resp> getUserManagerService_Hello(String TraceId, String userName) {
            log.info("[{}]dubbo 方式请求进入了!!!!", TraceId);
            Resp> mapData = gotoUserManagerService.createMapData();
            Map data = mapData.getData();
            data.put("TraceId", TraceId);
            data.put("userName", userName);
            return mapData;
        }
    
        @Override
        public Resp databaseUpdate(Object gpLogin) {
            Student gpLogin2 = null;
            if (gpLogin instanceof GpLogin) {
                Long id = ((GpLogin) gpLogin).getId();
                if (id != null && id > 0) {
                    // 插入本地数据库
                    gpLogin2 = new Student().
                            setUsername("thirdsysrouter")
                            .setPassword("thirdsysrouter")
                            .setPwdShow("分布式事务thirdsysrouter");
                    studentService.save(gpLogin2);
                    // 执照异常,利用分布式事务回滚  int i = 100 / 0;
                }
            }
            return gpLogin2 != null ? Resp.Ok(gpLogin2.getId()) : Resp.error("利用分布式事务");
        }
    }
    
    

    启动两个项目演示

    image

    输入项目一调用项目二的SwaggerUI接口测试地址

    http://localhost:10085/doc.html#/default/测试接口/getThirdSysRouterInDubboBySeataUsingGET

    image

    执行调用

    分析响应结果,由于手动制造了异常,被全局异常捕获,响应结果成功
    image

    查看A库A表和B库B表是否插入成功

    A库A表没有插入成功:分布式事务关键字的一条记录
    image
    B库B表没有插入成功:分布式事务关键字的一条记录
    image

    数据库结果是成功的,同时回滚了。。。

    查看日志

    A服务请求进入。执行了A库A表插入成功
    image

    继续日志Dubbo 去RPC调用B服务了

    2023-07-07 18:23:43.322 INFO 14568 --- [io-10085-exec-9] c.g.s.DubboRPCThirdSysRouterService : [7db0c75b-8a65-4d31-84cb-6cdd14d580a4] [Seata]:dubbo RPC方式请求发送出去!!!!

    B服务执行方法;B库B表插入成功响应-->A系统
    image

    A系统收到B'系统的响应:
    image
    A系统收到B'系统的响应继续走:触发除零异常
    image

    A系统:触发全局异常处理
    image
    image

    中间触发了这几个Seata二阶段提交的关键字日志
    image

    这时候意思很明显 失败回滚;去掉除零异常再测试

    代码优化一下:由前端传入参数控制是否触发异常区回滚
    image

    测试:界面返回操作成功
    image

    测试:数据库是否操作成功
    B系统:
    image
    A系统
    image

    验证通过。。。

    再测试失败全局事物回滚::

    image
    结束。。。。。。。。。。。。

    更详细参考Gitee完整的项目:https://gitee.com/gtnotgod/Springcloud-alibaba.git

  • 相关阅读:
    视频批量剪辑与分割:这些技巧帮你提高生成m3u8文件的效率
    iOS_Crash 四:的捕获和防护
    [附源码]计算机毕业设计springboot基于Java的日用品在线电商平台
    【Python程序设计】基于Flask的防疫宣传网站
    JavaScript正则表达式:正则表达式中的特殊字符
    深入了解软件测试:从入门到奥秘,揭开测试的精髓
    Genesis与Axis Ventures互动密切
    vim配置与使用
    这几本书看了之后在工作生活上都是有用的
    Java设计与实现“秒杀”活动之抢粽子【完整版】
  • 原文地址:https://www.cnblogs.com/gtnotgod/p/17535837.html