srping cloud alibaba micro service + seata actual combat

nacos+seata (seata highly available docker deployment, rancher deployment)

Description: record seata integration
1) Whole

  • Parent dependency
<properties>
        <!--Project compilation environment-->
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        
        <!--Dependent version management-->
        <fastjson.version>1.2.73</fastjson.version>
        <commons-lang3.version>3.11</commons-lang3.version>
        <spring-boot.version>2.2.10.RELEASE</spring-boot.version>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.3.RELEASE</spring-cloud-alibaba.version>
        <mysql-connector.version>8.0.16</mysql-connector.version>
        <druid-spring-boot-starter.version>1.2.4</druid-spring-boot-starter.version>
        <mybatis-plus-boot-starter.version>3.4.1</mybatis-plus-boot-starter.version>
    
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <!-- SpringBoot -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- SpringCloud -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- SpringCloud Alibaba -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- MySQL Database connection driver -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql-connector.version}</version>
            </dependency>
            <!-- MybatisPlus Mybatis Enhanced plug-in SpringBoot integration -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus-boot-starter.version}</version>
            </dependency>
            <!-- Druid Alibaba database connection pool -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid-spring-boot-starter.version}</version>
            </dependency>
            <!-- Ali FastJson -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>${fastjson.version}</version>
            </dependency>
            <!-- Apache Toolkit for processing basic data type data -->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>${commons-lang3.version}</version>
            </dependency>
            <!--Lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.22</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
  • Sub dependency
<dependencies>
        <!-- nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        
        <!-- seata-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <!-- Because of the compatible version,So it needs to eliminate its own seata My bag -->
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-all</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        
        
        
        <!--Introduce our own seata Dependency of corresponding version,Instead of using starter Default version-->
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-all</artifactId>
            <version>1.3.0</version>
        </dependency>
        
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>3.1.0</version>
        </dependency>
        
        <!--web starter-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3.2</version>
        </dependency>
        
        <!--alibaba druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>
        
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <version>2.6.1</version>
        </dependency>
        
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        
         <!--seata_account service-->
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>seata_account</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
         <!--seata_storage service-->
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>seata_storage</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>
Microservice profile
Note: in case of problem 1, you need to add file Conf and registry Conf file
  • bootstrap.yml
server:
  port: 7630

spring:
  application:
    name: account
  cloud:
    alibaba:
      seata:
        # The user-defined transaction group name needs to correspond to the name in seata server, which we previously configured in the configuration file of seata
        tx-service-group: order_tx_group
    nacos:
      discovery:
        server-addr: localhost:8860
    #        namespace: ffee2bbe-5ba5-4e6e-a822-6a00abe11769

  datasource:
    # Current data source operation type
    type: com.alibaba.druid.pool.DruidDataSource
    # mysql driver class
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/seata_account?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: 123

  logging:
    level:
      io:
        seata: info

  mybatis:
    mapperLocations: classpath*:mapper/*.xml

  • file.conf
transport {
  # tcp udt unix-domain-socket
  type = "TCP"
  #NIO NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  #thread factory for netty
  thread-factory {
    boss-thread-prefix = "NettyBoss"
    worker-thread-prefix = "NettyServerNIOWorker"
    server-executor-thread-prefix = "NettyServerBizHandler"
    share-boss-worker = false
    client-selector-thread-prefix = "NettyClientSelector"
    client-selector-thread-size = 1
    client-worker-thread-prefix = "NettyClientWorkerThread"
    # netty boss thread size,will not be used for UDT
    boss-thread-size = 1
    #auto default pin or 8
    worker-thread-size = 8
  }
  shutdown {
    # when destroy server, wait seconds
    wait = 3
  }
  serialization = "seata"
  compressor = "none"
}
service {
  #vgroup->rgroup
  vgroupMapping.order_tx_group = "default"
  #only support single node
  default.grouplist = "127.0.0.1:8091"
  #degrade current not support
  enableDegrade = false
  #disable
  disable = false
  #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
  max.commit.retry.timeout = "-1"
  max.rollback.retry.timeout = "-1"
}

client {
  async.commit.buffer.limit = 10000
  lock {
    retry.internal = 10
    retry.times = 30
  }
  report.retry.count = 5
}


## transaction log store, only used in seata-server
store {
  ## store mode: file,db,redis
  mode = "db"
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.cj.jdbc.Driver"
    url = "jdbc:mysql://172.16.1.240:33067/eplus_seata?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"
    user = "root"
    password = "xxx"
    minConn = 5
    maxConn = 30
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }
}
  • registry.conf
registry {
  # file ,nacos ,eureka,redis,zk,consul,etcd3,sofa
  type = "nacos"

  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8860"
    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:8860"
    namespace = ""
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
  }
}

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;
 

seata

AT mode

TC (transmission Coordinator) transaction coordinator: maintains the status of global and branch transactions and drives the submission or rollback of global transactions

TM (transmission manager) transaction manager: defines the scope of global transactions, starts global transactions, commits or rolls back global transactions

RM(Resource Manager) resource manager: manages the resources of branch transaction processing, talks with TC to register branch transactions and report the status of branch transactions, and drives branch transaction submission or rollback.

1) seata download (connection 1: seata download)

Download address: http://seata.io/zh-cn/blog/download.html

Version Description (nacos and seata versions): https://github.com/alibaba/spring-cloud-alibaba/wiki/ Version Description

2) File modification
  • file.conf

db mode is selected here

## transaction log store, only used in seata-server
service {
  #transaction service group mapping
  #Specifies the transaction group name for the test
  vgroupMapping.order_tx_group = "default"
  #only support when registry.type=file, please don't set multiple addresses
  #Specify the default group address and port, and you can set multiple addresses
  default.grouplist = "127.0.0.1:8091"
  #disable seata
  #Disable global transaction = false starts the service
  disableGlobalTransaction = false
}

store {
  ## store mode: file,db,redis
  mode = "db"
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.cj.jdbc.Driver"
    url = "jdbc:mysql://172.16.1.240:33067/eplus_seata?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"
    user = "root"
    password = "xxxx"
    minConn = 5
    maxConn = 30
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }
}

  • registry.conf

Note: Here I use nacos. For simplicity, other items are deleted and can be retained.

registry {
  # file ,nacos ,eureka,redis,zk,consul,etcd3,sofa
  type = "nacos"

  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8860"
    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:8860"
    namespace = ""
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
  }
}

  • config.txt

Note: only the necessary information is reserved here. Others have been deleted. Most of them are default parameters and can be configured as needed.

service.vgroupMapping.order_tx_group=default
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://172.16.1.240:33067/eplus_seata?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
store.db.user=root
store.db.password=xxx
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

  • Seata server database

Go to github to download seata, find the sql file in the (Figure:) directory, and select the corresponding

  • Register the configuration with nacos and view it
open git bash or linux Class command line, executing sh Script (note whether the script has permission to execute)
nacos-config.sh -h localhost -p 8860 -g SEATA_GROUP -t f46bbdaa-f11e-414f-9530-e6a18cbf91f6 -u nacos -w nacos

Parameter Description:
-g SEATA_GROUP(Group name)
-t f46bbdaa-f11e-414f-9530-e6a18cbf91f6 (Namespace id)  Remove-t Default to public

  • Launch and view

Operation effect

First, our Seata After the server is built, the database is generally used to build it. At this time, a database will be generated SeaTa There are three tables in the database: global_table,branch_table,lock_table Corresponding to global transaction, branch transaction and global lock respectively. 
global_table:  Every time a global transaction is initiated, the of the global transaction will be recorded in the table ID.  
branch_table:  Record the of each branch transaction ID,Information such as which database the branch transaction operates on
lock_table: Used to apply for a global lock.

springcloud alibaba project integration (actual case) effect:

Steps of the first stage: 
1)Start a global transaction in global_table Of global transactions generated in ID,And in branch_table Generate branch transactions in ID.  
2)In each local transaction: perform pre mirroring——>Execute business SQL->Perform post mirror——>Insert rollback log. 
Pre image: query and execute real business SQL Previous data. 
Post image: Business SQL The data after execution is used to verify whether the data is modified by other transactions during rollback. 
Insert rollback data: in the database UNDO_LOG Insert in table SQL Relevant information before and after execution( JSON String), used for two-phase rollback. 
3)Local transaction commit: SQL Implementation results and UNDO_LOG Commit the local transaction with the written data of the table. 
Phase II steps: 
1)Rollback: if the commit of any local transaction in a phase is wrong or timeout, the global rollback will be executed. 
adopt XID and Branch ID Find corresponding UNDO LOG The record verifies whether the current data is consistent with the post image data. The inconsistency indicates that other transactions have modified the data again; If so, pass UNDO LOG Execute rollback statement. Commit the local transaction after the rollback log is executed. 
2)Commit: when all local transactions in the first phase are successful, submit to the global transaction manager TC Returns the result of successful submission. 
In addition, delete the corresponding UNDO_LOG Logging.

seata parameters and concurrency problems

https://www.csdn.net/tags/NtTakg4sMTY5NzMtYmxvZwO0O0OO0O0O.html

common problem

1. Error reporting: endpoint format should like ip:port

Solution: (recommended method 2)

Method 1: add file to all microservices that register global transactions Conf and registry Conf file, the content is similar to the server, and The yml file configuration is shown in the figure below

Client port file Conf content

transport {
  # tcp udt unix-domain-socket
  type = "TCP"
  #NIO NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  #thread factory for netty
  thread-factory {
    boss-thread-prefix = "NettyBoss"
    worker-thread-prefix = "NettyServerNIOWorker"
    server-executor-thread-prefix = "NettyServerBizHandler"
    share-boss-worker = false
    client-selector-thread-prefix = "NettyClientSelector"
    client-selector-thread-size = 1
    client-worker-thread-prefix = "NettyClientWorkerThread"
    # netty boss thread size,will not be used for UDT
    boss-thread-size = 1
    #auto default pin or 8
    worker-thread-size = 8
  }
  shutdown {
    # when destroy server, wait seconds
    wait = 3
  }
  serialization = "seata"
  compressor = "none"
}
service {
  #vgroup->rgroup
  vgroupMapping.eplus_tx_group = "default"
  #only support single node
  default.grouplist = "127.0.0.1:8091"
  #degrade current not support
  enableDegrade = false
  #disable
  disable = false
  #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
  max.commit.retry.timeout = "-1"
  max.rollback.retry.timeout = "-1"
}

client {
  async.commit.buffer.limit = 10000
  lock {
    retry.internal = 10
    retry.times = 30
  }
  report.retry.count = 5
}


## transaction log store, only used in seata-server
store {
  ## store mode: file,db,redis
  mode = "db"
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.cj.jdbc.Driver"
    url = "jdbc:mysql://172.16.1.240:33067/eplus_seata?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"
    user = "root"
    password = "xxxx"
    minConn = 5
    maxConn = 30
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }
}


Client port registry Conf content

registry {
  # file ,nacos ,eureka,redis,zk,consul,etcd3,sofa
  type = "nacos"

  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"
  }
}

Method 2: configure all in yml file, as shown in the figure

2. The user-defined transaction group name needs to correspond to that in Seata server

tx-service-group: order_tx_group

3. The concurrent delivery thread is unsafe, dirty reading and writing may occur, and the inventory of delivered goods may become negative

1. First, let's transform the code of the official website into a code for ordering goods

    @GlobalTransactional
    public void purchase(String userId, String commodityCode, int orderCount) {
        try {
            Product product = productService.getById(commodityCode);
            if (product.getStock()-orderCount > 0) {
                //xxxxx
                ordersService.save(orders);
            }
        } catch (Exception e) {
            // TODO: handle exception
            throw new RuntimeException();
        }
    }

We can see that in this case, the thread is unsafe, dirty reading and writing will occur, and the delivered goods inventory may become negative

2. Modify the code lock to ensure thread safety

    @GlobalTransactional
    public void purchase(String userId, String commodityCode, int orderCount) {
        try {
            lock.lock();
            Product product = productService.getById(commodityCode);
            if (product.getStock()-orderCount  > 0) {
                //xxxx
                ordersService.save(orders);
            }
        } catch (Exception e) {
            // TODO: handle exception
            throw new RuntimeException();
        } finally {
            lock.unlock();
        }
    }

At this time, this code can be used normally However, it is found that the transaction timeout is easy to occur after the pressure test

You can see the rollback timeout after an exception occurs

Analyze the cause

1. According to the above code, we can see that there are more descriptions on the official website, all of which are annotation situations, and less api references. Let's first analyze the code just now

Service call - > discover annotation - > create transaction - > wait for lock - > acquire lock - > business processing

It can be found that priority has been given to the creation of transactions. At this time, if the concurrency is large and the lock cannot be obtained after waiting all the time At this time, various timeout exceptions shown in the above figure will be thrown

Solution

1. Let's look at the next process: service call - > find annotation - > create transaction - > wait for lock - > obtain lock - > business processing

2. Have you found the problem? As long as we can put the operation of waiting for lock and obtaining lock before creating transaction, this problem can be solved

User request - > wait for lock - > acquire lock - > service call - > discover annotation - > create transaction - > business processing

    @GetMapping(value = "purchase")
    public Object purchase() throws TransactionException {
        try {
            lock.lock();
            return demoService.purchase(1,2,3);
        } finally {
            // TODO: handle finally clause
            lock.unlock();
        }
    }

For example, the above code can be changed directly before calling, so that the lock in the service can also be removed and changed to the interface

3. What if someone says that a distributed lock is not a local lock, or that the place where I lock is in the service?

Never mind. seata also provides a set of transaction api creation methods

    public void xxx(String userId, String commodityCode, int orderCount) {
        try {
            lock.lock();
            Product product = xxxservic.getById(commodityCode);
            if (product.getStock()-orderCount  > 0) {
                GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
                tx.begin(300000, "test-group");
                try {
                    //Business code
                    tx.commit();
                } catch (Exception e) {
                    // TODO: handle exception
                    tx.rollback();
                }
            }
        } finally {
            lock.unlock();
        }
    }

Change to the above code and use the api to commit and rollback, so as to ensure that the transaction can be created only after the lock is robbed

Write isolation and read isolation of seata

seata single node deployment under linux+docker

  • Startup directory: (local mount)

    docker run --name seata -d -p 8091:8091  -v /home/work/seata/resources:/seata-server/resources seataio/seata-server:1.3.0
    
  • File copy

     docker cp 35116:/seata-server/resources /home/work/seata
    
  • View mount status

    docker inspect seata
    

seata cluster deployment under linux+docker

  • Startup directory: (local mount)

    docker run -d --restart always --name seata-server01 -p 8091:8091 -v /home/work/seata/resources:/seata-server/resources -e SEATA_IP=172.16.1.241 -e SEATA_PORT=8091 seataio/seata-server:1.3.0
    
    docker run -d --restart always --name seata-server02 -p 8092:8091 -v /home/work/seata/resources2:/seata-server/resources -e SEATA_IP=172.16.1.241 -e SEATA_PORT=8092 seataio/seata-server:1.3.0
    

Seata - rancher deployment

  • New configuration

  • Create a new Seata server service and mount the configuration

  • Service RM and TM registration

Related links:

Rapid integration of spring Cloud with Seata

https://github.com/seata/seata-samples/blob/master/doc/quick-integration-with-spring-cloud.md

seata Download Center

http://seata.io/zh-cn/blog/download.html

Corresponding Version Description

https://github.com/alibaba/spring-cloud-alibaba/wiki/ Version Description

Detailed case I

https://www.it235.com/ Advanced framework / springcloudalibaba / seata HTML # uses nacos as the configuration center for seata

Detailed case II of actual combat

https://blog.csdn.net/qq_40298902/article/details/108966561

Operation result description https://www.csdn.net/tags/MtTaEgysMTkzOTEwLWJsb2cO0O0O.html

seata parameter and concurrent dirty read and write problems

https://www.csdn.net/tags/NtTakg4sMTY5NzMtYmxvZwO0O0OO0O0O.html

seata official website

http://seata.io/zh-cn/docs/overview/what-is-seata.html

Detailed explanation of seata transaction grouping

https://blog.csdn.net/weixin_39800144/article/details/100740420

seata linux docker single node deployment

https://www.cnblogs.com/binz/p/12841125.html

Cluster deployment under seata linux docker

https://www.csdn.net/tags/NtjaQg0sMjczOTItYmxvZwO0O0OO0O0O.html

Added by attock on Wed, 26 Jan 2022 03:30:26 +0200