This is the 21st day of my participation in Gwen Challenge
Seata
An overview,
http://seata.io/zh-cn/docs/overview/what-is-seata.html
Two, environment configuration
Download and install
-
Download address https://github.com/seata/seata/releases/tag/v1.0.0
-
Unpack the
-
Modify the file.conf configuration file under \seata\conf
- The service module customizes the transaction name
vgroup_mapping.my_test_tx_group = "fsp_tx_group"
- Transaction log storage mode and database information
service { #transaction service group mapping vgroup_mapping.my_test_tx_group = "fsp_tx_group" #only support when registry.type=file, please don't set multiple addresses default.grouplist = "127.0.0.1:8091" #disable seata disableGlobalTransaction = false } store { ## store mode: file, db mode = "db" ## database store property db { ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc. datasource = "dbcp" ## mysql/oracle/h2/oceanbase etc. db-type = "mysql" driver-class-name = "com.mysql.jdbc.Driver" url = "jdbc:mysql://localhost:3306/seata" user = "root" password = "root" } } Copy the code
- The service module customizes the transaction name
-
SQL > seata-server-0.9.0\seata\conf
-
Modify the registry. Conf configuration file
registry { # File, NACOS, Eureka, Redis, ZK, Consul, ETCD3, SOFA type = "nacos" nacos { serverAddr = "localhost:8848" namespace = "" cluster = "default" } . } Copy the code
-
Start Nacos and Seata
SEATA’s distributed transaction solution
Business logic for users to purchase goods. The entire business logic is supported by three microservices:
- Storage service: deduct the storage quantity for a given item.
- Order service: Creates orders based on purchasing requirements.
- Account service: deducts balances from user accounts.
Database preparation
CREATE DATABASE seata_order;
USE seata_order;
CREATE TABLE t_order(
id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
user_id BIGINT(11) DEFAULT NULL COMMENT 'user id',
product_id BIGINT(11) DEFAULT NULL COMMENT 'product id',
count INT(11) DEFAULT NULL COMMENT 'number',
money DECIMAL(11.0) DEFAULT NULL COMMENT 'value',
status INT(1) DEFAULT NULL COMMENT 'Order Status: 0 in creation, 1 completed'
)ENGINE=InnoDB AUTO_INCREMENT=7 CHARSET=utf8;
CREATE DATABASE seata_storage;
USE seata_storage;
CREATE TABLE t_storage(
id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
product_id BIGINT(11) DEFAULT NULL COMMENT 'product id',
total INT(11) DEFAULT NULL COMMENT 'Gross inventory',
used INT(11) DEFAULT NULL COMMENT 'Used stock',
residue INT(11) DEFAULT NULL COMMENT 'Surplus stock'
)ENGINE=InnoDB AUTO_INCREMENT=7 CHARSET=utf8;
INSERT INTO t_storage(id, product_id, total, used, residue) VALUES(1.1.100.0.100);
CREATE DATABASE seata_account;
USE seata_account;
CREATE TABLE t_account(
id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
user_id BIGINT(11) DEFAULT NULL COMMENT 'user id',
total DECIMAL(10.0) DEFAULT NULL COMMENT 'Total amount',
used DECIMAL(10.0) DEFAULT NULL COMMENT 'Used amount',
residue DECIMAL(10.0) DEFAULT 0 COMMENT 'Remaining available amount'
)ENGINE=InnoDB AUTO_INCREMENT=7 CHARSET=utf8;
INSERT INTO t_account(id, user_id, total, used, residue) VALUES(1.1.1000.0.1000);
Copy the code
Create rollback log table
The SQL file is in \seata-server-0.9.0\seata\conf\db_undo_log.sql
Create tables for all four databases
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;
Copy the code
Microservice readiness
seata-order-service2001/seata-storage-service2002/seata-account-service2003
Rely on
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
Copy the code
The configuration file
server:
port: 2001
spring:
application:
name: seata-order-service
cloud:
alibaba:
seata:
# Change the transaction group name as specified in the configuration
tx-service-group: fsp_tx_group
nacos:
discovery:
server-addr: 127.0. 01.: 8848
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: JDBC: mysql: / / 47.95.226.96:3306 / seata? serverTimezone=GMT%2B8&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: admin
feign:
hystrix:
enabled: false
logging:
level:
io:
seata: info
mybatis:
mapper-locations: classpath:mapper/*.xml
Copy the code
Note: put the previously configuredfile.conf
andregistry.conf
Copied to theresources
Under the
Business code
test
Order module sends a GET request to http://localhost:2001/order/create? UserId = 1&productid =1&count=10&money=100, call Account module and storage module through Feign to reduce Account balance and inventory.
Existing problems
Now add a timeout operation to the Decrease method in the Account module
public void decrease(Long userId, BigDecimal money) {
LOGGER.info("-- -- -- -- -- -- -- -- -- AccountServiceImpl deductions -- -- -- -- -- -- -- -- --");
// Create timeout exception
try {
TimeUnit.SECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
accountDao.decrease(userId,money);
}
Copy the code
Continuing with the previous request, the order is created and the inventory is reduced, but the account balance is unchanged, violating the consistency of the data, using seATA distributed transaction resolution.
The solution
Annotate @globalTransactional at the entry point of the business
@GlobalTransactional
public void createOrder(Order order) {
LOGGER.info("------ New order -------");
orderDao.createOrder(order);
LOGGER.info("------Storage inventory reduction -------");
storageService.decrease(order.getProductId(), order.getCount());
LOGGER.info("-- -- -- -- -- - the Account deductions -- -- -- -- -- -- --");
accountService.decrease(order.getUserId(), order.getMoney());
LOGGER.info("------ Modify order status -------");
orderDao.updateOrder(order.getUserId(), 0);
LOGGER.info("------end-------");
}
Copy the code
Implementation process
The default mode is AT mode.
There are two stages:
- Phase 1: Parses the SQL and obtains two snapshots based on the SQL. One is pre-snapshot, which saves the data before the SQL execution, and the other is post-snapshot, which saves the data after the SQL execution.
- Stage 2:
- The snapshot is deleted
- If the command fails, the snapshot will be rewritten to the database and then deleted.