Seata入门
环境准备
- docker 安装 mysql
请移步https://blog.csdn.net/Zaric_001/article/details/113809164
-
建立数据库seata
-
导入表
/*
Navicat MySQL Data Transfer
Source Server : 192.168.1.11
Source Server Version : 50733
Source Host : 192.168.1.11:3306
Source Database : seata
Target Server Type : MYSQL
Target Server Version : 50733
File Encoding : 65001
Date: 2021-02-14 21:13:05
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `branch_table`
-- ----------------------------
DROP TABLE IF EXISTS `branch_table`;
CREATE TABLE `branch_table` (
`branch_id` bigint(20) NOT NULL,
`xid` varchar(128) NOT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`resource_group_id` varchar(32) DEFAULT NULL,
`resource_id` varchar(256) DEFAULT NULL,
`branch_type` varchar(8) DEFAULT NULL,
`status` tinyint(4) DEFAULT NULL,
`client_id` varchar(64) DEFAULT NULL,
`application_data` varchar(2000) DEFAULT NULL,
`gmt_create` datetime(6) DEFAULT NULL,
`gmt_modified` datetime(6) DEFAULT NULL,
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of branch_table
-- ----------------------------
-- ----------------------------
-- Table structure for `global_table`
-- ----------------------------
DROP TABLE IF EXISTS `global_table`;
CREATE TABLE `global_table` (
`xid` varchar(128) NOT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`status` tinyint(4) NOT NULL,
`application_id` varchar(32) DEFAULT NULL,
`transaction_service_group` varchar(32) DEFAULT NULL,
`transaction_name` varchar(128) DEFAULT NULL,
`timeout` int(11) DEFAULT NULL,
`begin_time` bigint(20) DEFAULT NULL,
`application_data` varchar(2000) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`xid`),
KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of global_table
-- ----------------------------
-- ----------------------------
-- Table structure for `lock_table`
-- ----------------------------
DROP TABLE IF EXISTS `lock_table`;
CREATE TABLE `lock_table` (
`row_key` varchar(128) NOT NULL,
`xid` varchar(96) DEFAULT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`branch_id` bigint(20) NOT NULL,
`resource_id` varchar(256) DEFAULT NULL,
`table_name` varchar(32) DEFAULT NULL,
`pk` varchar(36) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`row_key`),
KEY `idx_branch_id` (`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of lock_table
-- ----------------------------
- 在微服务所在数据库创建表
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 DEFAULT CHARSET=utf8;
- 准备seata配置文件
file.conf
注意: 此处是用mysql的容器进行数据库的操作的。在后面的执行中,seata-server容器会连接mysql容器,所以请把mysql容器名称定为mysql
url = “jdbc:mysql://mysql:3306/seata”
## transaction log store, only used in seata-server
store {
## store mode: file、db
mode = "db"
## file store property
file {
## store location dir
dir = "sessionStore"
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
maxBranchSessionSize = 16384
# globe session size , if exceeded throws exceptions
maxGlobalSessionSize = 512
# file buffer size , if exceeded allocate new buffer
fileWriteBufferCacheSize = 16384
# when recover batch read size
sessionReloadReadSize = 100
# async, sync
flushDiskMode = async
}
## database store property
db {
## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
datasource = "dbcp"
## mysql/oracle/h2/oceanbase etc.
dbType = "mysql"
driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://mysql:3306/seata"
user = "root"
password = "123456"
minConn = 1
maxConn = 10
globalTable = "global_table"
branchTable = "branch_table"
lockTable = "lock_table"
queryLimit = 100
}
}
registry.conf
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "file"
nacos {
serverAddr = "localhost"
namespace = ""
cluster = "default"
}
eureka {
serviceUrl = "http://localhost:8761/eureka"
application = "default"
weight = "1"
}
redis {
serverAddr = "localhost:6379"
db = "0"
}
zk {
cluster = "default"
serverAddr = "127.0.0.1:2181"
session.timeout = 6000
connect.timeout = 2000
}
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
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
}
etcd3 {
serverAddr = "http://localhost:2379"
}
file {
name = "file.conf"
}
}
-
docker 安装seata
docker pull seataio/seata-server
-
启动并挂载
此处挂载/root/docker-seata,下有两个文件夹,一个是config,下面有file.conf和registry.conf 还有一个是log用于存放日志。
docker run -d --name seata-server -p 8091:8091 --link mysql:mysql -e SEATA_CONFIG_NAME=file:/root/seata-config/registry -v /root/docker-seata/config:/root/seata-config -v //root/docker-seata/log:/root/logs -d seataio/seata-server
至此,环境准备就完毕了。
项目接入
-
pom
<!-- 分布式事务 --> <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>1.1.0</version> </dependency>
- application.properties
seata.enabled=true
#多个微服务 请保持id名称一致
seata.application-id=seate-server
# 分组名称
seata.tx-service-group=my_test_tx_group
seata.client.rm.async-commit-buffer-limit=1000
seata.client.rm.report-retry-count=5
seata.client.rm.table-meta-check-enable=false
seata.client.rm.report-success-enable=false
seata.client.rm.lock.retry-interval=10
seata.client.rm.lock.retry-times=30
seata.client.rm.lock.retry-policy-branch-rollback-on-conflict=true
seata.client.tm.commit-retry-count=5
seata.client.tm.rollback-retry-count=5
seata.client.undo.data-validation=true
seata.client.undo.log-serialization=jackson
seata.client.undo.log-table=undo_log
seata.client.log.exceptionRate=100
#my_test_tx_group 和配置的分组名称一直,且属性值default不要修改。
seata.service.vgroup-mapping.my_test_tx_group=default
#docker 中seata-server的访问地址
seata.service.grouplist.default=192.168.1.11:8091
seata.transport.shutdown.wait=3
seata.transport.thread-factory.boss-thread-prefix=NettyBoss
seata.transport.thread-factory.worker-thread-prefix=NettyServerNIOWorker
seata.transport.thread-factory.server-executor-thread-prefix=NettyServerBizHandler
seata.transport.thread-factory.share-boss-worker=false
seata.transport.thread-factory.client-selector-thread-prefix=NettyClientSelector
seata.transport.thread-factory.client-selector-thread-size=1
seata.transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThread
seata.transport.thread-factory.worker-thread-size=default
seata.transport.thread-factory.boss-thread-size=1
seata.transport.type=TCP
seata.transport.server=NIO
seata.transport.heartbeat=true
seata.transport.serialization=seata
seata.transport.compressor=none
seata.transport.enable-client-batch-send-request=true
备注的属性需要调整,其余看具体环境,一般不用调整。
-
数据源代理配置
import com.alibaba.druid.pool.DruidDataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import javax.sql.DataSource; @Configuration public class DatabaseConfiguration { /** * autowired datasource config */ @Autowired private DataSourceProperties dataSourceProperties; /** * init durid datasource * * @Return: druidDataSource datasource instance */ @Bean @Primary public DruidDataSource druidDataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setUrl(dataSourceProperties.getUrl()); druidDataSource.setUsername(dataSourceProperties.getUsername()); druidDataSource.setPassword(dataSourceProperties.getPassword()); druidDataSource.setDriverClassName(dataSourceProperties.getDriverClassName()); druidDataSource.setInitialSize(0); druidDataSource.setMaxActive(180); druidDataSource.setMaxWait(60000); druidDataSource.setMinIdle(0); druidDataSource.setValidationQuery("Select 1 from DUAL"); druidDataSource.setTestOnBorrow(false); druidDataSource.setTestOnReturn(false); druidDataSource.setTestWhileIdle(true); druidDataSource.setTimeBetweenEvictionRunsMillis(60000); druidDataSource.setMinEvictableIdleTimeMillis(25200000); druidDataSource.setRemoveAbandoned(true); druidDataSource.setRemoveAbandonedTimeout(1800); druidDataSource.setLogAbandoned(true); return druidDataSource; } /** * init mybatis sqlSessionFactory * @Param: dataSourceProxy datasource proxy * @Return: DataSourceProxy datasource proxy */ @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources("classpath*:/mapper/*.xml")); return factoryBean.getObject(); } }
-
调用示例
@GlobalTransactional(timeoutMills = 300000, name = "base2020-seata-example") //name可以修改 @Override public void update(Double acccount) { Bank1 bank1 = bank1Dao.selectByPrimaryKey(2l); bank1.setAccountBalance(bank1.getAccountBalance()-acccount); bank1Dao.updateByPrimaryKeySelective(bank1); String modify = bank2Feign.modify(acccount+""); if(modify.equals("error")){ throw new RuntimeException("分支处理失败");//看是否成功 }else{ System.out.println("ok"); } }
-
查看数据库的操作结果。
-
日志
成功
2021-02-14 12:43:47.036 INFO --- [ NettyServerNIOWorker_1_1_4] i.s.c.r.processor.server.RegTmProcessor : TM register success,message:RegisterTMRequest{applicationId='seate-server', transactionServiceGroup='my_test_tx_group'},channel:[id: 0x3a404bfd, L:/172.17.0.4:8091 - R:/192.168.1.4:58903],client version:1.1.0
2021-02-14 12:43:47.043 INFO --- [ batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler : SeataMergeMessage timeout=300000,transactionName=base2020-seata-example
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:43:47.043 INFO --- [ ServerHandlerThread_1_45_500] i.s.s.coordinator.DefaultCoordinator : Begin new global transaction applicationId: seate-server,transactionServiceGroup: my_test_tx_group, transactionName: base2020-seata-example,timeout:300000,xid:172.17.0.4:8091:36130662144475151
2021-02-14 12:43:47.155 INFO --- [ ServerHandlerThread_1_46_500] i.s.c.r.processor.server.RegRmProcessor : RM register success,message:RegisterRMRequest{resourceIds='jdbc:mysql://192.168.1.11:3306/bank1', applicationId='seate-server', transactionServiceGroup='my_test_tx_group'},channel:[id: 0x76bfd1a0, L:/172.17.0.4:8091 - R:/192.168.1.4:58904],client version:1.1.0
2021-02-14 12:43:47.169 INFO --- [ batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler : SeataMergeMessage xid=172.17.0.4:8091:36130662144475151,branchType=AT,resourceId=jdbc:mysql://192.168.1.11:3306/bank1,lockKey=account_info:2
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:43:47.169 INFO --- [ ServerHandlerThread_1_47_500] i.seata.server.coordinator.AbstractCore : Register branch successfully, xid = 172.17.0.4:8091:36130662144475151, branchId = 36130662144475152, resourceId = jdbc:mysql://192.168.1.11:3306/bank1 ,lockKeys = account_info:2
2021-02-14 12:43:47.755 INFO --- [ batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler : SeataMergeMessage xid=172.17.0.4:8091:36130662144475151,extraData=null
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:43:48.619 INFO --- [ AsyncCommitting_1_1] io.seata.server.coordinator.DefaultCore : Committing global transaction is successfully done, xid = 172.17.0.4:8091:36130662144475151.
2021-02-14 12:44:05.814 INFO --- [ batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler : SeataMergeMessage timeout=300000,transactionName=base2020-seata-example
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:44:05.814 INFO --- [ ServerHandlerThread_1_50_500] i.s.s.coordinator.DefaultCoordinator : Begin new global transaction applicationId: seate-server,transactionServiceGroup: my_test_tx_group, transactionName: base2020-seata-example,timeout:300000,xid:172.17.0.4:8091:36130662144475153
2021-02-14 12:44:05.916 INFO --- [ batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler : SeataMergeMessage xid=172.17.0.4:8091:36130662144475153,branchType=AT,resourceId=jdbc:mysql://192.168.1.11:3306/bank1,lockKey=account_info:2
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:44:05.916 INFO --- [ ServerHandlerThread_1_1_500] i.seata.server.coordinator.AbstractCore : Register branch successfully, xid = 172.17.0.4:8091:36130662144475153, branchId = 36130662144475154, resourceId = jdbc:mysql://192.168.1.11:3306/bank1 ,lockKeys = account_info:2
2021-02-14 12:44:06.089 INFO --- [ batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler : SeataMergeMessage xid=172.17.0.4:8091:36130662144475153,extraData=null
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:44:06.618 INFO --- [ AsyncCommitting_1_1] io.seata.server.coordinator.DefaultCore : Committing global transaction is successfully done, xid = 172.17.0.4:8091:36130662144475153.
失败
2021-02-14 12:41:55.581 INFO --- [ ServerHandlerThread_1_41_500] i.s.s.coordinator.DefaultCoordinator : Begin new global transaction applicationId: seate-server,transactionServiceGroup: my_test_tx_group, transactionName: base2020-seata-example,timeout:300000,xid:172.17.0.4:8091:36130662144475149
2021-02-14 12:41:55.581 INFO --- [ batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler : SeataMergeMessage timeout=300000,transactionName=base2020-seata-example
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:41:56.323 INFO --- [ batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler : SeataMergeMessage xid=172.17.0.4:8091:36130662144475149,branchType=AT,resourceId=jdbc:mysql://192.168.1.11:3306/bank1,lockKey=account_info:2
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:41:56.323 INFO --- [ ServerHandlerThread_1_42_500] i.seata.server.coordinator.AbstractCore : Register branch successfully, xid = 172.17.0.4:8091:36130662144475149, branchId = 36130662144475150, resourceId = jdbc:mysql://192.168.1.11:3306/bank1 ,lockKeys = account_info:2
2021-02-14 12:41:58.114 INFO --- [ batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler : SeataMergeMessage xid=172.17.0.4:8091:36130662144475149,extraData=null
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:41:58.202 INFO --- [ ServerHandlerThread_1_43_500] io.seata.server.coordinator.DefaultCore : Rollback branch transaction successfully, xid = 172.17.0.4:8091:36130662144475149 branchId = 36130662144475150
2021-02-14 12:41:58.203 INFO --- [ ServerHandlerThread_1_43_500] io.seata.server.coordinator.DefaultCore : Rollback global transaction successfully, xid = 172.17.0.4:8091:36130662144475149.