1. nacos服务的部署这里就不介绍了,先启动nacos服务,用于注册/发现、配置中心
  2. 下载seata服务的压缩包,https://github.com/seata/seata/releases
  3. 下载seata开发源码包,主要是用到一些配置文件
  4. 解压seata服务压缩包,修改registry.conf文件
  5. registry {
      # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
      type = "nacos"
      loadBalance = "RandomLoadBalance"
      loadBalanceVirtualNodes = 10
    
      nacos {
        application = "seata-server"
        serverAddr = "127.0.0.1:8848"
        group = "SEATA_GROUP"
        namespace = ""
        cluster = "default"
        username = "nacos"
        password = "nacos"
      }
    }
    
    config {
      # file、nacos 、apollo、zk、consul、etcd3
      type = "nacos"
    
      nacos {
        serverAddr = "127.0.0.1:8848"
        namespace = ""
        group = "SEATA_GROUP"
        username = "nacos"
        password = "nacos"
      }
    }
  6. 网上很多帖子都是先改file.conf,完全没必要,file.conf是针对本地配置时使用的,我们采用的是nacos作为注册和配置中心,所以file.conf不需要
  7. 修改config.txt,服务解压包里没有,从开发源码包里找,位于seata-develop.zip\seata-develop\script\config-center 目录下,复制到seata根目录
  8. transport.type=TCP
    transport.server=NIO
    transport.heartbeat=true
    transport.enableClientBatchSendRequest=false
    transport.threadFactory.bossThreadPrefix=NettyBoss
    transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
    transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
    transport.threadFactory.shareBossWorker=false
    transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
    transport.threadFactory.clientSelectorThreadSize=1
    transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
    transport.threadFactory.bossThreadSize=1
    transport.threadFactory.workerThreadSize=default
    transport.shutdown.wait=3
    transport.serialization=seata
    transport.compressor=none
    service.vgroupMapping.my_test_tx_group=default
    service.default.grouplist=127.0.0.1:8091
    service.enableDegrade=false
    service.disableGlobalTransaction=false
    client.rm.asyncCommitBufferLimit=10000
    client.rm.lock.retryInterval=10
    client.rm.lock.retryTimes=30
    client.rm.lock.retryPolicyBranchRollbackOnConflict=true
    client.rm.reportRetryCount=5
    client.rm.tableMetaCheckEnable=false
    client.rm.sqlParserType=druid
    client.rm.reportSuccessEnable=false
    client.rm.sagaBranchRegisterEnable=false
    client.tm.commitRetryCount=5
    client.tm.rollbackRetryCount=5
    client.tm.defaultGlobalTransactionTimeout=60000
    client.tm.degradeCheck=false
    client.tm.degradeCheckAllowTimes=10
    client.tm.degradeCheckPeriod=2000
    client.undo.dataValidation=true
    client.undo.logSerialization=jackson
    client.undo.onlyCareUpdateColumns=true
    client.undo.logTable=undo_log
    store.mode=db
    store.file.dir=file_store/data
    store.file.maxBranchSessionSize=16384
    store.file.maxGlobalSessionSize=512
    store.file.fileWriteBufferCacheSize=16384
    store.file.flushDiskMode=async
    store.file.sessionReloadReadSize=100
    store.db.datasource=druid
    store.db.dbType=mysql
    store.db.driverClassName=com.mysql.jdbc.Driver
    store.db.url=jdbc:mysql://127.0.0.1:3306/db_seata?useUnicode=true
    store.db.user=root
    store.db.password=root
    store.db.minConn=5
    store.db.maxConn=30
    store.db.globalTable=global_table
    store.db.branchTable=branch_table
    store.db.queryLimit=100
    store.db.lockTable=lock_table
    store.db.maxWait=5000
    store.redis.host=127.0.0.1
    store.redis.port=6379
    store.redis.maxConn=10
    store.redis.minConn=1
    store.redis.database=0
    store.redis.password=null
    store.redis.queryLimit=100
    server.recovery.committingRetryPeriod=1000
    server.recovery.asynCommittingRetryPeriod=1000
    server.recovery.rollbackingRetryPeriod=1000
    server.recovery.timeoutRetryPeriod=1000
    server.maxCommitRetryTimeout=-1
    server.maxRollbackRetryTimeout=-1
    server.rollbackRetryTimeoutUnlockEnable=false
    server.undo.logSaveDays=7
    server.undo.logDeletePeriod=86400000
    log.exceptionRate=100
    metrics.enabled=false
    metrics.registryType=compact
    metrics.exporterList=prometheus
    metrics.exporterPrometheusPort=9898

    主要修改点为store.mode=db,store.db.url=jdbc:mysql://127.0.0.1:3306/db_seata?useUnicode=true,store.db.user=root,store.db.password=root,这个配置表示seata服务端使用数据库存储,根据自己实际情况填写

  9. 将nacos-config.sh复制到seata的conf目录,目录为:seata-develop.zip\seata-develop\script\config-center\nacos
  10. 用命令将配置文件导入到nacos配置中心,sh nacos-config.sh -h 127.0.0.1 -p 8848 -g SEATA_GROUP
  11. seata服务的表创建语句
  12. 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客户端建表语句,也就是各个微服务使用的数据库都要有表,用于事务回滚

  13. -- for AT mode you must to init this sql for you business database. the seata server not need it.
    CREATE TABLE IF NOT EXISTS `undo_log`
    (
        `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(6)  NOT NULL COMMENT 'create datetime',
        `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
        UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
    ) ENGINE = InnoDB
      AUTO_INCREMENT = 1
      DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';
    

    启动seata服务,从bin目录双击seata-server.bat

  14. 接下来是重头了,代码阶段,我这里是分三个工程,一个consumer,二个provider
  15. pom.xml完全一样
  16. <?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>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.11.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>cn.demo</groupId>
        <artifactId>seata-consumer</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>seata-consumer</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.22</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.2</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.10</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>com.alibaba.cloud</groupId>
                    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                    <version>2.2.3.RELEASE</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Hoxton.SR9</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
    </project>

    consumer工程的application.yml

  17. server:
      port: 8080
    spring:
      datasource:
        druid:
          driverClassName: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/db_test?useUnicode=true&characterEncoding=utf-8&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
          username: root
          password: root
      application:
        name: seata-consumer
      cloud:
        nacos:
          server-addr: 127.0.0.1:8848
    seata:
      enabled: true
      application-id: seata-consumer
      tx-service-group: my_test_tx_group
      enable-auto-data-source-proxy: true
      use-jdk-proxy: false
      excludes-for-auto-proxying: firstClassNameForExclude,secondClassNameForExclude
      config:
        type: nacos
        nacos:
          namespace: ""
          server-addr: 127.0.0.1:8848
          group: SEATA_GROUP
          username: "nacos"
          password: "nacos"
      registry:
        type: nacos
        nacos:
          application: seata-server
          server-addr: 127.0.0.1:8848
          group: "SEATA_GROUP"
          namespace: ""
          username: "nacos"
          password: "nacos"

    provider1的application.yml

  18. server:
      port: 8081
    spring:
      datasource:
        druid:
          driverClassName: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/db_test?useUnicode=true&characterEncoding=utf-8&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
          username: root
          password: root
      application:
        name: seata-provider1
      cloud:
        nacos:
          server-addr: 127.0.0.1:8848
    seata:
      enabled: true
      application-id: seata-provider1
      tx-service-group: my_test_tx_group
      enable-auto-data-source-proxy: true
      use-jdk-proxy: false
      config:
        type: nacos
        nacos:
          namespace: ""
          server-addr: 127.0.0.1:8848
          group: SEATA_GROUP
          username: "nacos"
          password: "nacos"
      registry:
        type: nacos
        nacos:
          application: seata-server
          server-addr: 127.0.0.1:8848
          group: "SEATA_GROUP"
          namespace: ""
          username: "nacos"
          password: "nacos"

    provider2的application.yml与1的基本一样,改spring.application.mane和seata.application-id两个属性为2的

  19. consumer工程的代码
  20. @EnableFeignClients
    @SpringBootApplication
    @MapperScan("cn.daixinmei.seata")
    public class SeataConsumerApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(SeataConsumerApplication.class, args);
    	}
    
    }
    
    
    @RestController
    public class MainController {
    
        @Autowired
        private MainService mainService;
    
        @RequestMapping("test1")
        public String test1() {
            mainService.test1();
            return "来了!";
        }
    
        @RequestMapping("test2")
        public String test2() {
            mainService.test2();
            return "来了!";
        }
    
        @RequestMapping("test3")
        public String test3() {
            mainService.test3();
            return "来了!";
        }
    }
    
    @Service
    @GlobalTransactional
    public class MainService {
    
        @Autowired
        private Provider1 provider1;
    
        @Autowired
        private Provider2 provider2;
    
        public void test1() {
            provider1.test1();
            provider2.test1();
        }
    
        public void test2() {
            provider1.test1();
            provider2.test2();
        }
    }
    
    @FeignClient("seata-provider1")
    public interface Provider1 {
    
        @RequestMapping("test1")
        public String test1();
    }
    
    @FeignClient("seata-provider2")
    public interface Provider2 {
    
        @RequestMapping("test1")
        public String test1();
    
        @RequestMapping("test2")
        void test2();
    }

    provider1工程代码

  21. @SpringBootApplication
    @MapperScan("cn.daixinmei.seata")
    public class SeataProvider1Application {
    
    	public static void main(String[] args) {
    		SpringApplication.run(SeataProvider1Application.class, args);
    	}
    
    }
    
    
    @RestController
    public class MainController {
    
        @Autowired
        private MainService mainService;
    
        @RequestMapping("test1")
        public String test1() {
            mainService.test1();
            return "来了!";
        }
    }
    
    @Service
    @Transactional
    public class MainService {
    
        @Autowired
        private MainDao mainDao;
    
        private AtomicInteger i = new AtomicInteger();
    
        public void test1() {
            mainDao.insert(UUID.randomUUID().toString(), "第一个服务 - " + i.incrementAndGet());
        }
    }
    
    public interface MainDao {
    
        @Insert("insert into t_seata (id,name) values (#{id},#{name})")
        void insert(@Param("id") String id, @Param("name") String name);
    }

    provider2工程代码

  22. @SpringBootApplication
    @MapperScan("cn.daixinmei.seata")
    public class SeataProvider2Application {
    
    	public static void main(String[] args) {
    		SpringApplication.run(SeataProvider2Application.class, args);
    	}
    
    }
    
    @RestController
    public class MainController {
    
        @Autowired
        private MainService mainService;
    
        @RequestMapping("test1")
        public String test1() {
            mainService.test1();
            return "来了!";
        }
    
        @RequestMapping("test2")
        public String test2() {
            mainService.test2();
            return "来了!";
        }
    }
    
    @Service
    @Transactional
    public class MainService {
    
        @Autowired
        private MainDao mainDao;
    
        private AtomicInteger i = new AtomicInteger();
    
        public void test1() {
            mainDao.insert(UUID.randomUUID().toString(), "第二个服务 - " + i.incrementAndGet());
        }
    
        public void test2() {
            mainDao.insert(UUID.randomUUID().toString(), "第二个服务 - " + i.incrementAndGet());
            System.out.println(1 / 0);
        }
    }
    
    public interface MainDao {
    
        @Insert("insert into t_seata (id,name) values (#{id},#{name})")
        void insert(String id, String name);
    }

    都是我自己的demo代码,可以启动,没有问题

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐