AT transaction of spring cloud transaction
1seata server TC global transaction coordinator
Seata Server - TC global transaction coordinator
AT transaction has three roles: TC (Transaction Coordinator), TM (transaction manager) and RM (Resource Manager). TM and RM are embedded in business applications, while TC is an independent service.
Seata Server is TC, which can be downloaded and started directly from the official warehouse. Download address: https://github.com/seata/seata/releases
Seata Server configuration
There are two profiles for Seata Server:
- seata/conf/registry.conf
- seata/conf/file.conf
Seata Server needs to register with the registry so that other services can discover and communicate with Seata Server through the registry.
Seata supports a variety of registry services: nacos, eureka, redis, zk, consumer, etcd3 and sofa.
In our project, we need to use the eureka registry, the connection address of eureka service and the registered service name, which need to be in registry Configure in the conf file:
registry.conf file
registry { # file ,nacos ,eureka,redis,zk,consul,etcd3,sofa # Select eureka registration configuration here type = "eureka" nacos { ...... } # Registration configuration of eureka eureka { # Address of Registration Center serviceUrl = "http://localhost:8761/eureka" # Registered service ID application = "seata-server" weight = "1" } redis { ...... } ......
file.conf
Seata needs to store global transaction information, branch transaction information and global lock information. Where are these data stored?
For the configuration of storage location, it can be placed in the configuration center or in local files. The configuration center services supported by Seata Server include: nacos, apollo, zk, consumer, etcd3.
Here we choose the simplest one and use the local file, which needs to be in registry Conf configuration file
file.conf configures the storage location of transaction information. The storage location supports file, db and redis.
Here, we choose the database as the storage location, which needs to be in file Configure in conf:
store { ## store mode: file,db,redis # Select database storage here mode = "db" ## file store property file { ...... } # Database storage 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.jdbc.Driver" # Database connection configuration url = "jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8" user = "root" password = "root" minConn = 5 maxConn = 30 # Transaction log table name setting globalTable = "global_table" branchTable = "branch_table" lockTable = "lock_table" queryLimit = 100 maxWait = 5000 } ## redis store property redis { ...... } }
The recipient will be seata-server-1.3.0 Download the zip file, put it into a file directory that does not contain Chinese, and unzip it
2 startup parameter setting
Enter the bin directory and find Seata server The bat file is opened using a text file, and 85 lines are found,
Change the memory configuration (the purpose is to reduce the memory configuration and save memory)
%JAVACMD% %JAVA_OPTS% -server -Xmx2048m -Xms2048m -Xmn1024m -Xss512k -XX:Sur......
Change to
%JAVACMD% %JAVA_OPTS% -server -Xmx256m -Xms256m -Xmn128m -Xss512k -XX:Sur......
The data used for the storage of this project is stored, so you need to modify the file in conf Contents stored in files in conf
Modify the file in the conf directory Files in conf
Modify registry. In the conf directory Conf file
Start Seata Server
Start the Eureka registry first
Enter the bin directory of Seata Server and double-click Seata Server Bat starts the Seata Server.
To view the registration information of Seata Server in Eureka registry:
Add Seata AT transaction to order service
Order calls inventory and account. Let's start with the previous order.
To start a global transaction in an order item, you also need to execute the branch transaction of order saving.
3. Add seata dependency
Add seata dependency to order parent
POM of order parent There is a commented out seata dependency in the XML file, and you can open it now
POM of order parent The contents of the XML file are as follows:
<?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.3.12.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>cn.tedu</groupId> <artifactId>order-parent</artifactId> <version>0.0.1-SNAPSHOT</version> <name>order-parent</name> <description>Demo project for Spring Boot</description> <properties> <mybatis-plus.version>3.3.2</mybatis-plus.version> <druid-spring-boot-starter.version>1.1.23</druid-spring-boot-starter.version> <seata.version>1.3.0</seata.version> <spring-cloud-alibaba-seata.version>2.0.0.RELEASE</spring-cloud-alibaba-seata.version> <spring-cloud.version>Hoxton.SR6</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</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-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${druid-spring-boot-starter.version}</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-seata</artifactId> <version>${spring-cloud-alibaba-seata.version}</version> <exclusions> <exclusion> <artifactId>seata-all</artifactId> <groupId>io.seata</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-all</artifactId> <version>${seata.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </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.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.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
4. Configure the order module
Configure application in order YML file, TC transaction coordinator organizes multiple services into a global transaction through "transaction group". When each service starts, it needs to register with TC and join the same transaction group.
Add a transaction group in the order module
spring: ...... cloud: alibaba: seata: tx-service-group: order_tx_group ......
You need to obtain the address of TC from the registry. Configure the address of the registry here.
registry.conf file content
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" } }
file. Configuration in conf
Here we specify the service ID Seata server of TC:
vgroupMapping.order_tx_group = "seata-server"
order_tx_group corresponds to application Transaction group name registered in YML.
# Which coordinator does the transaction group use # Transaction group name = coordinator service name vgroupMapping.order_tx_group = "seata-server"
file.conf file content
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 # order_ tx_ Group is consistent with the configuration of "TX service group: order_tx_group" in yml # "Seata server" is consistent with the registered name of TC server # Get the address of Seata server from eureka, register yourself with Seata server and set group # Which coordinator does the transaction group use # Transaction group name = coordinator service name vgroupMapping.order_tx_group = "seata-server" #only support when registry.type=file, please don't set multiple addresses order_tx_group.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 } }
Document storage
5 create seata data source agent
Seata AT transaction has no intrusion into business code and fully automates the processing of global transactions. Its function is realized by Seata's data source agent tool.
Here, we create the data source proxy of Seata and exclude the default data source of Spring.
package cn.tedu.order; import com.alibaba.druid.pool.DruidDataSource; import io.seata.rm.datasource.DataSourceProxy; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import javax.sql.DataSource; @Configuration public class DatasourceConfiguration { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource druidDataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); return druidDataSource; } @Primary @Bean("dataSource") public DataSourceProxy dataSource(DataSource druidDataSource){ return new DataSourceProxy(druidDataSource); } }
Exclude the default data source of Springboot from the main program:
Add the following comments on the main program
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
Because the source configuration url of seat is inconsistent with datasource, it should be in application Add a new data source connection to YML
jdbcUrl: jdbc:mysql://localhost:3307/seata_order?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
6 start global transaction
Seata AT has no business intrusion, so it is very simple to start a global transaction. You only need to add a @ GlobalTransactional annotation.
In addition, we add global transactions step by step and test them. Here, we note out the storage and account calls.
Enter CN. In the order module tedu. order. Servie package, find the OrderServiceImpl implementation class, and add global transactions to the create method,
@GlobalTransactional
7 start up test
Start services in order:
1.Eureka
2.Seata Server
3.Easy Id Generator
4.Order
Call to save the order, address:
http://localhost:8083/create?userId=1&productId=1&count=10&money=100
Observe the console to see that the global transaction and the branch transaction of the order have been started, and you can see the global transaction ID (XID) and branch transaction ID (Branch ID):
Then observe the newly added order data in the database:
8 simulate rollback
Test exceptions and rollback
Add a simulated exception to the OrderServiceImpl business code and try again:
throw new RuntimeException("Simulation anomaly");
Restart the order project and call save order:
http://localhost:8083/create?userId=1&productId=1&count=10&money=100
You can see the log of global transaction rollback:
After the test, you can comment out the simulation exception
9 add SeataAT transactions to the storage module
First, give the storage application YML file configuration transaction group
#The group name of the transaction group cloud: alibaba: seata: tx-service-group: order_tx_group
Put the file in the resiurces folder in the order module Conf and registry Copy the conf file to the resources folder in the storage module.
Create seata data source proxy
Add CN. In the order module tedu. Copy the DSAutoConfiguration under the order package to CN. Under the storage module tedu. Storage package
Exclude the DataSourceAutoConfiguration autoconfiguration class from the main program annotation
Add on the main startup class
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
In application Add a new seat data source configuration in the YML configuration file
jdbcUrl: jdbc:mysql://localhost:3307/seata_storage?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
Start branch transaction
Add @ Transactional annotation on business method to start local transaction:
Under the storage item CN tedu. storage. Add @ Transactional annotation to the decrease method under the StorageServiceImpl implementation class in the service package
package cn.tedu.storage.service; import cn.tedu.storage.mapper.StorageMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class StorageServiceImpl implements StorageService{ @Autowired private StorageMapper storageMapper; @Transactional @Override public void decrease(Long productId, Integer count) { storageMapper.decrease(productId,count); } }
In the OrderServiceImpl business code of order, call the item to reduce the inventory
Previously, we commented out the calling commodity inventory, and now open the comment:
10 start the storage project
Start projects in order:
1.Eureka
2.Seata Server
3.Easy Id Generator
4.Storage
5.Order
Call to save the order, address:
http://localhost:8083/create?userId=1&productId=1&count=10&money=100
Add a new piece of data to the order database
Data reduction in storage database
The order will call inventory, and the two services will start a branch transaction respectively. The two branch transactions together form a global transaction:
Observe that the console of the two projects has the log of Seata AT transactions. The console of the Storage project is as follows:
Console of order module
11 simulation abnormality
Add a simulated exception to the business code in the storage module and try again:
throw new RuntimeException("Simulation anomaly");
Restart the storage project and call save order:
http://localhost:8083/create?userId=1&productId=1&count=10&money=100
The Order module rolled back
An exception occurred in the storage module
It can be concluded that the data is rolled back
After the storage module is tested, remove the comments
11account module adds SeataAT transaction
First, in the account module, click appplication To add a transaction group to YML, add it under spring configuration
#The group name of the transaction group cloud: alibaba: seata: tx-service-group: order_tx_group
File. In the resources folder of the order project conf,registry. The conf file is copied to the same folder as account
Create seata data source proxy
The same as the data source agent in order items and inventory items, the order module CN tedu. Copy the DSAutoConfiguration in the order package to CN. Of account tedu. In account
Exclude the DataSourceAutoConfiguration configuration from the main startup class, and add the following annotation to the main startup class
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
Because the database url attribute name of hikari is JDBC url, not url, you need to add a configuration of JDBC url in the configuration file
jdbcUrl: jdbc:mysql://localhost:3307/seata_account?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8
Start branch transaction
Annotate the local transaction on the AccoutServiceImpl business
Invoke the amount of deducted account in the business class of order
We commented out the calling account earlier, and now open the comment:
12 start the account project for testing
Start projects in order:
Eureka
Seata Server
Easy Id Generator
Storage
Account
Order
Call to save the order, address:
http://localhost:8083/create?userId=1&productId=1&count=10&money=100
The order will call inventory and account, and the three services will start a branch transaction respectively. The three branch transactions together form a global transaction:
Observe that the console of the three projects has the log of Seata AT transactions. The console of the account project is as follows:
order console
Storage Console
Account console
Then observe the order table, inventory table and account table in the database.
order table
storage table
account table
13 abnormal test Account
Add exception information in the business class accountserviceimpl of Account
throw new RuntimeException("Simulation anomaly");
Restart the account project and call save order:
http://localhost:8083/create?userId=1&productId=1&count=10&money=100
Check the database tables order, storage and account. If the execution is successful, new orders will be added, inventory will be reduced and amount will be deducted. If the execution fails, the data will not change and will be rolled back.
In case of failure, you can see the rollback log in the order, storage and account console.
order console
Stopage console
account console
View database tables
account table
order table
Stopage table
After completion, remove the exception comment of account
Transaction completion for SeataAT