zoukankan      html  css  js  c++  java
  • 微服务应用整合SEATA实现分布式事务

    概要

    seata 是alibaba 出的一款分布式事务管理器,他有侵入性小,实现简单等特点。我们能够使用seata 实现分布式事务管理,

    是微服务必备的组件。他可以实现在微服务之间的事务管理,也可以实现多个数据源的事务管理。

    seata 在阿里内部,和众多的公司都有应用,因此我们可以放心的使用它。

    实现的基本原理

    SEATA 实现了几种事务模式,我们使用AT模式,他使用起来简单,代码侵入性小。

    下图就是AT的事务过程。

    TM是事务管理者

    RM 资源管理者,可以认为是数据库。

    TC 是事务协调者,就是SEATA 服务

    TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID。
    XID 在微服务调用链路的上下文中传播。
    RM 向 TC 注册分支事务,将其纳入 XID 对应全局事务的管辖。
    TM 向 TC 发起针对 XID 的全局提交或回滚决议。
    TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。

     实现方式

    配置SEATA

    引入相关JAR包

    <dependency>
                    <groupId>com.alibaba.cloud</groupId>
                    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
                    <version>2.1.1.RELEASE</version>
                    <scope>compile</scope>
                    <exclusions>
                        <exclusion>
                            <groupId>io.seata</groupId>
                            <artifactId>seata-all</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
    
                <dependency>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-all</artifactId>
                    <version>1.2.0</version>
                </dependency>

    在resources 下增加文件 registry.conf,我的实现为使用nacos作为配置和注册中心

    文件内容如下:

    registry {
      type = "nacos"
      nacos {
        application = "seata-server"
        serverAddr = "192.168.31.10:8848"
        #namespace = "public"
        group = "DEFAULT_GROUP"
        #cluster = "default"
        #username = "nacos"
        #password = "nacos"
      }
    }
    
    config {
      type = "nacos"
      nacos {
        serverAddr = "192.168.31.10:8848"
        namespace = ""
        group = "SEATA_GROUP"
        cluster = "default"
        username = "nacos"
        password = "nacos"
      }
    }

    第一段是注册中心的配置,第二段为配置中心的配置,配置实际上是放到nacos 下的。

    配置文件路径:

    https://gitee.com/seata-io/seata/blob/develop/script/config-center/config.txt

    可以把这个下下来,然后使用命令将这个配置,提交到 nacos,命令的路径为:

    https://gitee.com/seata-io/seata/tree/develop/script/config-center/nacos

     我们可以如下执行命令:

    nacos-config.sh -h nacos的IP -p nacos端口 -u nacos用户名 -w nacos密码

    这个配置需要修改的地方:

    service.vgroupMapping.bpm_tx_group=default
    service.vgroupMapping.form_tx_group=default
    service.vgroupMapping.portal_tx_group=default
    service.vgroupMapping.user_tx_group=default
    service.vgroupMapping.system_tx_group=default

    这个配置 为 

    service.vgroupMapping + 应用的配置 =default 

     这个default 对应上面的配置

     事务数据存储到数据库

     修改 数据库的配置,我们将配置导入到nacos 。

     同时,需要将刚刚的配置文件 registry.conf 拷贝到 seata 目录下

     配置好后需要先启动 nacos,在启动 seata

     nohup ./seata-server.sh -p 8888 -h 192.168.31.10 &

    seata 数据库脚本:

    https://gitee.com/seata-io/seata/blob/develop/script/server/db/mysql.sql

    这样 事务配置就处理好了。

    我们需要在微服务的每个数据库中增加 UNDO_LOG表。

    CREATE TABLE IF NOT EXISTS `undo_log`
    (
        `id`            BIGINT(20)   NOT NULL AUTO_INCREMENT COMMENT 'increment id',
        `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     NOT NULL COMMENT 'create datetime',
        `log_modified`  DATETIME     NOT NULL COMMENT 'modify datetime',
        PRIMARY KEY (`id`),
        UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
    ) ENGINE = InnoDB
      AUTO_INCREMENT = 1
      DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

    这个需要和微服务数据库在一起。

    代码实现

    @Bean("dataSource")
        @ConfigurationProperties(prefix = "spring.datasource")
        public DruidDataSource druidDataSource() {
            return new DruidDataSource();
        }
    
    
    
        @Bean("dataSourceProxy")
        public DataSourceProxy dataSourceProxy(@Qualifier("dataSource")DataSource dataSource) {
            DataSourceProxy proxy=new DataSourceProxy(dataSource);
            return proxy;
        }

     实际上我们在代码中使用的是 DataSourceProxy 代理过的数据源。

    测试如下:

     在测试时,我们可以发现,通过RootContext  取得Xid。

  • 相关阅读:
    ECMAScript 继承继承机制实现
    ECMAScript 函数定义类或对象
    药品查询APP开发流程(五)开发—yao_search.js
    ECMAScript 函数修改对象
    药品查询APP开发流程(六)开发—yao_category.js
    药品查询APP开发流程(四)开发—app.js
    药品查询APP开发流程(一)需求分析
    药品查询APP开发流程(三)开发—SQLite数据库
    ECMAScript 继承继承机制实例
    求最长递减子序列(转载)
  • 原文地址:https://www.cnblogs.com/yg_zhang/p/13061286.html
Copyright © 2011-2022 走看看