• 分布式事务( XA) seata eurake springboot mysql (1.4.2)


    官网文档:        https://seata.io/zh-cn/docs/user/configurations.html
    官网示例代码: https://github.com/seata/seata-samples

    1. 下载 : https://github.com/seata/seata/releases   (版本1.4.2)

    2. 安装:  (建议docker)

    3. 修改配置:

    file.conf

    改动如下:

    mode = "db"
    url = "jdbc:mysql://192.168.186.122:3306/seata?rewriteBatchedStatements=true"
    user = "root"
    password = "root"

    创建db  seata   ,初始化 db 脚本:    可以下载源码  https://github.com/seata/seata/releases ,然后在  /source_seata-1.4.2/script/server/db/mysql.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(128),
        `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;
    View Code

    /opt/seata-server-1.4.2/conf/registry.conf

    改动如下 :

      type = "eureka"
      eureka {
        serviceUrl = "http://icil:icil4icil@192.168.18.204:8761/eureka"
        application = "sea-seata"
        weight = "1"
      }

    启动 即可

    bin/seata-server.sh

     ######################  使用  #########################

     整合: springboot + euraka  + seata + mysql 

     1. 创建项目

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.sea</groupId>
        <artifactId>sea-goods-service</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>sea-goods-service</name>
        <description>Demo project for Spring Boot</description>
    
    <!--    <parent>
            <groupId>com.sea</groupId>
            <artifactId>shopsea</artifactId>
            <version>1.0-SNAPSHOT</version>
            <relativePath/>
        </parent>-->
    
        <properties>
            <java.version>1.8</java.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <spring-boot.version>2.3.12.RELEASE</spring-boot.version>
            <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
            <spring.admin.version>2.1.6</spring.admin.version>
            <!-- Log4j2漏洞-->
            <log4j2.version>2.15.0</log4j2.version>
            <apollo.version>1.5.0</apollo.version>
            <fastjson.version>1.2.76</fastjson.version>
            <swagger.version>2.9.2</swagger.version>
            <common.io.version>2.11.0</common.io.version>
        </properties>
    
        <dependencies>
    
            <!-- seata 依赖 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-seata</artifactId>
                <version>2.1.0.RELEASE</version>
                <exclusions>
                    <exclusion>
                        <groupId>io.seata</groupId>
                        <artifactId>seata-all</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <!-- https://mvnrepository.com/artifact/io.seata/seata-spring-boot-starter -->
    <!--        <dependency>
                <groupId>io.seata</groupId>
                <artifactId>seata-spring-boot-starter</artifactId>
                <version>1.4.2</version>
            </dependency>-->
            <dependency>
                <groupId>io.seata</groupId>
                <artifactId>seata-all</artifactId>
                <version>1.4.2</version>
            </dependency>
    
          <!--  <dependency>
                <groupId>com.sea</groupId>
                <artifactId>sea-common</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>-->
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.21</version>
            </dependency>
    
    
    
    
            <dependency>
                <groupId>de.codecentric</groupId>
                <artifactId>spring-boot-admin-starter-client</artifactId>
                <version>${spring.admin.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-mongodb</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.kafka</groupId>
                <artifactId>spring-kafka</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
    
            <!-- <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency> -->
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>
    
             <!--3rd part-->
            <!-- 缓存 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-cache</artifactId>
            </dependency>
            <!-- ehcache -->
            <dependency>
                <groupId>net.sf.ehcache</groupId>
                <artifactId>ehcache</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.jcraft</groupId>
                <artifactId>jsch</artifactId>
                <version>0.1.55</version>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
                <version>2.6.1</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>${fastjson.version}</version>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>${swagger.version}</version>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>${swagger.version}</version>
            </dependency>
    
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>${common.io.version}</version>
            </dependency>
            <dependency>
                <groupId>com.ctrip.framework.apollo</groupId>
                <artifactId>apollo-client</artifactId>
                <version>${apollo.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-dependencies</artifactId>
                    <version>${spring-boot.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>${spring-boot.version}</version>
                </plugin>
    
            </plugins>
        </build>
    
    </project>
    View Code

    application.properties

    ###### mysql  #####
    ### database sea_address configure
    jdbc.datasource.address.jdbc-url=jdbc:mysql://192.168.18.136:3306/sea_address
    jdbc.datasource.address.driverClassName=com.mysql.cj.jdbc.Driver
    #jdbc.datasource.address.driverClassName=com.mysql.jdbc.Driver
    jdbc.datasource.address.username=root
    jdbc.datasource.address.password=root
    jdbc.datasource.address.sql-script-encoding=UTF-8
    ### database sea_user configure
    jdbc.datasource.user.jdbc-url=jdbc:mysql://192.168.18.136:3306/sea_user
    jdbc.datasource.user.driverClassName=com.mysql.cj.jdbc.Driver
    jdbc.datasource.user.username=root
    jdbc.datasource.user.password=root
    jdbc.datasource.user.sql-script-encoding=UTF-8

    MySqlDataSourceConfig
    //说明: XA 模式必须需要使用DatasourceProxy , 并且需要在当前业务数据库中 新建一个 undo_log 表, 用于保存需要回滚的数据
    
    import io.seata.rm.datasource.DataSourceProxy;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.jdbc.core.JdbcTemplate;
    import javax.sql.DataSource;
    /***************************
     *<pre>
     * @Project Name : seata_research
     * @Package      : com.sea.shop.config
     * @File Name    : MySqlDataSourceConfig
     * @Author       :  Sea
     * @Date         : 7/29/22 10:01 AM
     * @Purpose      :
     * @History      :
     *</pre>
     ***************************/
    @Configuration
    public class MySqlDataSourceConfig {
    
    
        @Bean(name = "addressDataSource")
        @Qualifier("addressDataSource")
        @ConfigurationProperties("jdbc.datasource.address")
        public DataSource addressDataSource() {
            return DataSourceBuilder.create().build();
        }
      

      //说明: XA 模式必须需要使用DatasourceProxy , 并且需要在当前业务数据库中 新建一个 undo_log 表, 用于保存需要回滚的数据 @Qualifier(
    "addressDataSourceProxy") @Bean("addressDataSourceProxy") public DataSourceProxy addressDataSourceProxy( @Qualifier("addressDataSource") DataSource dataSource) { return new DataSourceProxy(dataSource); } @Bean(name = "addressJdbcTemplate") public JdbcTemplate addressJdbcTemplate(@Qualifier("addressDataSourceProxy") DataSourceProxy addressDataSourceProxy) { return new JdbcTemplate(addressDataSourceProxy); }   //####################### user ################################3 @Bean(name = "userDataSource") @Qualifier("userDataSource") @ConfigurationProperties("jdbc.datasource.user") public DataSource userDataSource() { return DataSourceBuilder.create().build(); } @Qualifier("userDataSourceProxy") @Bean("userDataSourceProxy") public DataSourceProxy userDataSourceProxy( @Qualifier("userDataSource") DataSource dataSource) { return new DataSourceProxy(dataSource); } @Bean(name = "userJdbcTemplate") public JdbcTemplate userJdbcTemplate(@Qualifier("userDataSourceProxy") DataSourceProxy userDataSourceProxy) { return new JdbcTemplate(userDataSourceProxy); } }

    在resource 下添加seata  client 的配置文件   file.conf    registry.conf  (项目启动会自动加载)  (注意里面的配置要和 seata-server 一致)

       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 = "sea-seata"
      #only support when registry.type=file, please don't set multiple addresses
      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
      }
    }
    View Code
    registry.conf
    registry {
      # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
      type = "eureka"
    
      nacos {
        application = "seata-server"
        serverAddr = "127.0.0.1:8848"
        group = "SEATA_GROUP"
        namespace = ""
        cluster = "default"
        username = ""
        password = ""
      }
      eureka {
        serviceUrl = "http://icil:icil4icil@192.168.18.204:8761/eureka"
        application = "sea-seata"
        weight = "1"
      }
      redis {
        serverAddr = "localhost:6379"
        db = 0
        password = ""
        cluster = "default"
        timeout = 0
      }
      zk {
        cluster = "default"
        serverAddr = "127.0.0.1:2181"
        sessionTimeout = 6000
        connectTimeout = 2000
        username = ""
        password = ""
      }
      consul {
        cluster = "default"
        serverAddr = "127.0.0.1:8500"
        aclToken = ""
      }
      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
      type = "file"
    
      nacos {
        serverAddr = "127.0.0.1:8848"
        namespace = ""
        group = "SEATA_GROUP"
        username = ""
        password = ""
        dataId = "seataServer.properties"
      }
      consul {
        serverAddr = "127.0.0.1:8500"
        aclToken = ""
      }
      apollo {
        appId = "seata-server"
        ## apolloConfigService will cover apolloMeta
        apolloMeta = "http://192.168.1.204:8801"
        apolloConfigService = "http://192.168.1.204:8080"
        namespace = "application"
        apolloAccesskeySecret = ""
        cluster = "seata"
      }
      zk {
        serverAddr = "127.0.0.1:2181"
        sessionTimeout = 6000
        connectTimeout = 2000
        username = ""
        password = ""
        nodePath = "/seata/seata.properties"
      }
      etcd3 {
        serverAddr = "http://localhost:2379"
      }
      file {
        name = "file.conf"
      }
    }
    View Code
    
    

    2. 初始化业务数据库

    CREATE SCHEMA `sea_user` ;
    CREATE SCHEMA `sea_address` ;

     创建表

    CREATE TABLE sea_user.user (
      `id` int(11) NOT NULL,
      `name` varchar(45) DEFAULT NULL,
      `age` varchar(45) DEFAULT NULL,
      `mark` varchar(45) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    SELECT * FROM sea_user.undo_log;
    
    
    
    CREATE TABLE sea_address.address (
      `id` int(11) NOT NULL,
      `country` varchar(45) DEFAULT NULL,
      `provinces` varchar(45) DEFAULT NULL,
      `city` varchar(45) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

    3.分别在两个数据库中 添加 undo_log 表

    在业务相关的数据库中添加 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

    4.  测试分布式事务    分别像两个db 插入数据, 手动添加异常 ,看数据是否都保存了 

     另外 (feign) 调用,  在调用的service 层 方法加上 @GlobalTransactional  然后直接调用即可  (此处不贴代码)

     业务代码:

    @Service
    public class SeatesHandler {
        @Autowired
        @Qualifier("addressJdbcTemplate")
        private JdbcTemplate addressJdbcTemplate;
        @Autowired
        @Qualifier("userJdbcTemplate")
        public JdbcTemplate userJdbcTemplate;
        @Autowired
        private  OrderServiceClient orderServiceClient;
       /**
         * @param no
         * @param isExp  
         */
        @GlobalTransactional
        public void insert(int no, Boolean isExp) {
            orderServiceClient.add(no);
            userJdbcTemplate.update("INSERT INTO user (id,name,age) VALUES (?,?,?)",no,"sea",21);
            addressJdbcTemplate.update ("INSERT INTO address (id,country,provinces,city) VALUES (?,?,?,?)",no,"cn","gd","sz");
            if(isExp){
                        int i= 1/0;
            }
            List<Map<String, Object>> mapsUser = userJdbcTemplate.queryForList("select * from user");
            List<Map<String, Object>> mapsAddress = addressJdbcTemplate.queryForList("select * from address");
            System.err.println("user" + mapsUser);
            System.err.println("address" + mapsAddress);
    //        int update = userJdbcTemplate.update("delete from user where id=?", 1);
    //        int update1 = addressJdbcTemplate.update("delete from address where id=?", 1);
        }
    }

    接口测试:

       @Autowired
        SeatesHandler seatesHandler;
    
        @GetMapping("addToPd")
        public String addToOrder(@RequestParam Integer no,Boolean isExp) {
             seatesHandler.insert(no,isExp);
             return "ok";
        }
  • 相关阅读:
    匀速不间断旋转动画
    调用底层不能直接访问的类和方法
    当SD卡拔出时,返回首页,栈中的activity都要清除,只留下首页的activity
    Android 视频播放器切换到下个视频时残留上个视频画面的解决办法
    监听SD卡状态
    Android之SeekBar定制
    setRequestedOrientation设置屏幕方向
    【初级算法】15. 有效的字母异位词
    【初级算法】14. 字符串中的第一个唯一字符
    【初级算法】13. 颠倒整数
  • 原文地址:https://www.cnblogs.com/lshan/p/16533280.html
Copyright © 2020-2023  润新知