zoukankan      html  css  js  c++  java
  • Seata实现Sprincloud(Eureka+Feign)事务

    目录

    说明
    步骤
    实战

    基本环境的配置
    调用方和服务方的共同配置

    事务的实现
    拓展

    说明

    谨以此记录学习 Seata 时踩过的坑
    项目是一个微服务的架构,需要使用到“分布式事务”,在折腾了tx-lcn、tcc-transaction等几个玩意儿后,最终把目光定格在seata上,决定用seata给基于Eureka+Feign的项目添加分布式事务管理。

    资料如下:

    步骤

    1. 下载、配置、运行 Seata Server
      Seata 需要使用 Server 端的配合来实现分布式事务,因此需要先部署 Seata 的 Server 环境。

    2. 配置共同环境
      服务的调用方以及服务提供方,都需要进行一些共同的、一致的配置。

    3. 配置各自的环境
      其实就是给服务调用方加上全局事务(分布式事务)的注解"@GlobalTransactional",服务提供方不需要额外配置。

    实战

    下载、配置并运行SeataServer

    下载

    下载地址:
    http://seata.io/zh-cn/blog/download.html

    Seata 1.2.0 (2020-04-20) 目录结构如下:

    bin用于运行Seata Server; lib是server用到的资源库,无需理会; conf是配置文件目录。



    bat为win下脚本文件; sh为unix-like系统下的脚本。



    关注file.conf与register.conf

    配置

    根据自己需求修改配置文件—— "file.conf" 和 "registry.conf"。文章开头已贴出服务端以及应用端(客户端)配置项的说明的地址。

    file.conf

    此次需要用到数据库来保存 "undo_log" 等等的数据,需要在"file.conf"修改保存模式"mode"为"db",修改"db"中数据库相关的配置:

    store {
      ## store mode: file、db
      mode = "db"
    
      ## database store property
      db {
        ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
        datasource = "druid"
        ## mysql/oracle/postgresql/h2/oceanbase etc.
        dbType = "mysql"
        driverClassName = "com.mysql.jdbc.Driver"
        url = "jdbc:mysql://localhost:3306/seata_server"
        user = "root"
        password = "root"
        minConn = 5
        maxConn = 30
        globalTable = "global_table"
        branchTable = "branch_table"
        lockTable = "lock_table"
        queryLimit = 100
        maxWait = 5000
      }
    }
    

    mode = "db" 表明事务信息用db存储,当mode="db"时,只有db节点下的配置生效,不用管file节点

    registry.conf

    同样根据自己需求修改。
    seata server会把自己注册到注册中心,像其它的微服务模块一样。registry.conf就是配置seata server使用何种注册中心以及如何注册。
    registry节点为服务注册中心的类型及配置,此处选择type=eureka并修改对应的eureka的配置。

    registry {
      # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
      type = "eureka"
    
      eureka {
        serviceUrl = "http://localhost:8761/eureka"
        application = "default"
        weight = "1"
      }
    }
    
    #配置中心的配置,根据自己需求修改,eureka不支持充当配置中心,保留默认值
    config {
      # file、nacos 、apollo、zk、consul、etcd3
      ...
      ...
    }
    

    运行

    根据操作系统类型选择脚本运行。

    基本环境的配置

    由于此处使用数据库存储事务相关的数据,所以应先建库、建表。sql如下:

    -- -------------------------------- The script used when storeMode is 'db' --------------------------------
    -- the table to store GlobalSession data
    CREATE TABLE IF NOT EXISTS `global_table`
    (
        `xid`                       VARCHAR(128) NOT NULL,
        `transaction_id`            BIGINT,
        `status`                    TINYINT      NOT NULL,
        `application_id`            VARCHAR(32),
        `transaction_service_group` VARCHAR(32),
        `transaction_name`          VARCHAR(128),
        `timeout`                   INT,
        `begin_time`                BIGINT,
        `application_data`          VARCHAR(2000),
        `gmt_create`                DATETIME,
        `gmt_modified`              DATETIME,
        PRIMARY KEY (`xid`),
        KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
        KEY `idx_transaction_id` (`transaction_id`)
    ) ENGINE = InnoDB
      DEFAULT CHARSET = utf8;
    
    -- the table to store BranchSession data
    CREATE TABLE IF NOT EXISTS `branch_table`
    (
        `branch_id`         BIGINT       NOT NULL,
        `xid`               VARCHAR(128) NOT NULL,
        `transaction_id`    BIGINT,
        `resource_group_id` VARCHAR(32),
        `resource_id`       VARCHAR(256),
        `branch_type`       VARCHAR(8),
        `status`            TINYINT,
        `client_id`         VARCHAR(64),
        `application_data`  VARCHAR(2000),
        `gmt_create`        DATETIME(6),
        `gmt_modified`      DATETIME(6),
        PRIMARY KEY (`branch_id`),
        KEY `idx_xid` (`xid`)
    ) ENGINE = InnoDB
      DEFAULT CHARSET = utf8;
    
    -- the table to store lock data
    CREATE TABLE IF NOT EXISTS `lock_table`
    (
        `row_key`        VARCHAR(128) NOT NULL,
        `xid`            VARCHAR(96),
        `transaction_id` BIGINT,
        `branch_id`      BIGINT       NOT NULL,
        `resource_id`    VARCHAR(256),
        `table_name`     VARCHAR(32),
        `pk`             VARCHAR(36),
        `gmt_create`     DATETIME,
        `gmt_modified`   DATETIME,
        PRIMARY KEY (`row_key`),
        KEY `idx_branch_id` (`branch_id`)
    ) ENGINE = InnoDB
      DEFAULT CHARSET = utf8;
    

    seata github直达

    调用方和服务方的共同配置

    数据库

    以上是基本的数据表。另外,每个被调用的服务以及服务的调用方都需要用到 "undo_log"表用于事务的回滚,sql如下:

    -- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
    CREATE TABLE `undo_log` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `branch_id` bigint(20) NOT NULL,
      `xid` varchar(100) NOT NULL,
      `context` varchar(128) NOT NULL,
      `rollback_info` longblob NOT NULL,
      `log_status` int(11) NOT NULL,
      `log_created` datetime NOT NULL,
      `log_modified` datetime NOT NULL,
      `ext` varchar(100) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
    

    maven依赖:

    <!--seata-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-seata</artifactId>
        <version>2.1.0.RELEASE</version>
        <exclusions>
            <exclusion>
                <artifactId>seata-all</artifactId>
                <groupId>io.seata</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>io.seata</groupId>
        <artifactId>seata-all</artifactId>
        <version>1.2.0</version>
    </dependency>
    

    其它的配置文件


    需要在resource目录下创建 "file.conf" 和 "registry.conf" 文件。这两个文件与之前下载的seata目录里面的配置文件不是一样的,两者内容如下:
    file.conf

    transport {
      # tcp udt unix-domain-socket
      type = "TCP"
      #NIO NATIVE
      server = "NIO"
      #enable heartbeat
      heartbeat = true
      # the client batch send request enable
      enableClientBatchSendRequest = true
      #thread factory for netty
      threadFactory {
        bossThreadPrefix = "NettyBoss"
        workerThreadPrefix = "NettyServerNIOWorker"
        serverExecutorThread-prefix = "NettyServerBizHandler"
        shareBossWorker = false
        clientSelectorThreadPrefix = "NettyClientSelector"
        clientSelectorThreadSize = 1
        clientWorkerThreadPrefix = "NettyClientWorkerThread"
        # netty boss thread size,will not be used for UDT
        bossThreadSize = 1
        #auto default pin or 8
        workerThreadSize = "default"
      }
      shutdown {
        # when destroy server, wait seconds
        wait = 3
      }
      serialization = "seata"
      compressor = "none"
    }
    service {
      #transaction service group mapping
      vgroupMapping.my_test_tx_group = "default"
      #only support when registry.type=file, please don't set multiple addresses
      #关于grouplist,只有当registry.type=file,注册中心是file方式时,才会起作用。 https://blog.csdn.net/weixin_39800144/article/details/100726116
      default.grouplist = "127.0.0.1:8091"
      #degrade, current not support
      enableDegrade = false
      #disable seata
      disableGlobalTransaction = false
    }
    
    client {
      rm {
        asyncCommitBufferLimit = 10000
        lock {
          retryInterval = 10
          retryTimes = 30
          retryPolicyBranchRollbackOnConflict = true
        }
        reportRetryCount = 5
        tableMetaCheckEnable = false
        reportSuccessEnable = false
      }
      tm {
        commitRetryCount = 5
        rollbackRetryCount = 5
      }
      undo {
        dataValidation = true
        logSerialization = "jackson"
        logTable = "undo_log"
      }
      log {
        exceptionRate = 100
      }
    }
    

    registry.conf:

    registry {
      # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
      type = "eureka"
    
      nacos {
        serverAddr = "localhost"
        namespace = ""
        cluster = "default"
      }
      eureka {
        serviceUrl = "http://localhost:8761/eureka"
        application = "default"
        weight = "1"
      }
      redis {
        serverAddr = "localhost:6379"
        db = "0"
        password = ""
        cluster = "default"
        timeout = "0"
      }
      zk {
        cluster = "default"
        serverAddr = "127.0.0.1:2181"
        session.timeout = 6000
        connect.timeout = 2000
        username = ""
        password = ""
      }
      consul {
        cluster = "default"
        serverAddr = "127.0.0.1:8500"
      }
      etcd3 {
        cluster = "default"
        serverAddr = "http://localhost:2379"
      }
      sofa {
        serverAddr = "127.0.0.1:9603"
        application = "default"
        region = "DEFAULT_ZONE"
        datacenter = "DefaultDataCenter"
        cluster = "default"
        group = "SEATA_GROUP"
        addressWaitTime = "3000"
      }
      file {
        name = "file.conf"
      }
    }
    
    config {
      # file、nacos 、apollo、zk、consul、etcd3、springCloudConfig
      type = "file"
    
      nacos {
        serverAddr = "localhost"
        namespace = ""
        group = "SEATA_GROUP"
      }
      consul {
        serverAddr = "127.0.0.1:8500"
      }
      apollo {
        app.id = "seata-server"
        apollo.meta = "http://192.168.1.204:8801"
        namespace = "application"
      }
      zk {
        serverAddr = "127.0.0.1:2181"
        session.timeout = 6000
        connect.timeout = 2000
        username = ""
        password = ""
      }
      etcd3 {
        serverAddr = "http://localhost:2379"
      }
      file {
        name = "file.conf"
      }
    }
    

    可根据自己需求修改,一般情况下默认值即可。
    参考:

    application.yml的配置

    application.yml:

    spring:
      cloud:
        alibaba:
          seata:
            tx-service-group: my_test_tx_group
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/xx
        username: root
        password: root
    

    启动类的配置

    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
    

    seata 需要使用代理的 DataSource, 因此不使用 DataSourceAutoConfiguration

    事务的实现

    基本的配置已经实现,被调用的服务的方法(即服务提供方的方法)不需要做额外的配置,只需要在调用方(即需要通过feign调用其它服务)的方法上添加 "@GlobalTransactional" 注解,如:

    @GlobalTransactional(name = "fsp-create-order", rollbackFor = Exception.class)
    public void createOrder(Param param){
        //通过feign调用其它服务
        accountFeign.checkAccount();
        productFeign.checkNum();
    }
    

    拓展


      在client端的配置文件"file.conf"中,可以看到如上的service节点,红框部分是事务组的名称,官方说该名称应该和Server中的配置保持一致,然而在1.2.0版本的seata server端的配置文件中找不到该配置项...所以此处保留了sample的名称,此时可以运行成功。seata的文档真是一言难尽...
      项目是使用eureka作为注册中心,而在文章开头也提到对seata配置文件registry.conf的修改,把type改为"eureka",即把seata server注册到eureka中,此时,"vgroupMapping.my_test_tx_group"的值"default",就是seata server在eureka中的Application name:

    参考:

  • 相关阅读:
    .NET文件格式相关开源项目
    ASP.NET配置文件Web.config 详细解释
    Allow user to select camera or gallery for image
    android之调用webservice 实现图片上传
    使用 iTextSharp 生成 PDF 表格
    Android:如何显示网络图片
    Android的HttpClient和WebView session不同的问题
    提高你开发效率的十五个Visual Studio 2010使用技巧
    HTML5 Audio/Video 标签,属性,方法,事件汇总
    ASP.NET Web 项目文件类型
  • 原文地址:https://www.cnblogs.com/life-of-coding/p/13216986.html
Copyright © 2011-2022 走看看