官网文档:        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";
    }

 

posted on 2022-07-29 18:58  lshan  阅读(184)  评论(0编辑  收藏  举报