一、Seata-Server
1.1 下载
官方下载地址 :https://seata.io/zh-cn/blog/download.html
1.2 启动
Seata-Server 是开箱即用的,启动 bin
目录下的 seata-server.bat
或者 seata-server.sh
即可
另外可以根据需求添加一些参数,输入 seata-server.sh --help
即可查看参数
1 2 3 4 5 6 7 8 9 10 11 12 13
| Options: --host, -h 注册到注册中心的ip --port, -p 监听的端口,默认8091 --storeMode, -m 日志存储模式:文件、数据库 默认文件 --serverNode, -n 服务节点id,默认通过雪花算法生成 --seataEnv, -e 用于多配置隔离的环境名称 --help
|
seata-server 的默认启动端口是8091,如果我们要指定18091,只需 seata-server.sh -p 18091
即可
二、Spring Cloud 服务搭建
2.1 pom 依赖
1 2 3
| <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-seata</artifactId></dependency>
|
2.2 配置
2.2.1 registry.conf
在 resources
资源目录下配置 registry.conf
配置文件
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| registry { # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa type = "file"
nacos { application = "seata-server" serverAddr = "localhost" namespace = "" username = "" password = "" } eureka { serviceUrl = "http://localhost:8761/eureka" weight = "1" } redis { serverAddr = "localhost:6379" db = "0" password = "" timeout = "0" } zk { serverAddr = "127.0.0.1:2181" sessionTimeout = 6000 connectTimeout = 2000 username = "" password = "" } consul { serverAddr = "127.0.0.1:8500" } etcd3 { serverAddr = "http://localhost:2379" } sofa { serverAddr = "127.0.0.1:9603" region = "DEFAULT_ZONE" datacenter = "DefaultDataCenter" 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" username = "" password = "" } consul { serverAddr = "127.0.0.1:8500" } apollo { appId = "seata-server" apolloMeta = "http://192.168.1.204:8801" namespace = "application" } zk { serverAddr = "127.0.0.1:2181" sessionTimeout = 6000 connectTimeout = 2000 username = "" password = "" } etcd3 { serverAddr = "http://localhost:2379" } file { name = "file.conf" } }
|
该文件指定了 seata 的注册中心和配置中心,如果没有注册中心和配置中心也可指定为文件的形式。最终指定的形式由 registry.type
和 config.type
来决定,如示例中就选择以 file 的形式来作为配置信息
2.2.2 file.conf
以 file 形式做注册和配置时,需在 resources
目录下创建 file.conf
(registry.conf 中所配置的文件),如果采用其它的方式则不需要该文件。该文件主要配置 seata 的 ip、端口等信息,示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| 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 vgroup_mapping.my_test_tx_group = "default" #only support when registry.type=file, please don't set multiple addresses default.grouplist = "localhost: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 } }
|
2.2.3 application.yml
除开数据源等其它配置,最主要的配置如下:
1 2 3 4 5 6 7 8 9
| spring: application: name: storage-gts-seata-example cloud: alibaba: seata: tx-service-group: my_test_tx_group
|
2.2.4 数据源配置
1 2 3 4 5 6 7 8 9 10 11
| @Configuration @ConditionalOnClass(DruidDataSource.class) @AutoConfigureBefore(DataSourceAutoConfiguration.class) public class MyDataSourceConfig { @Primary @Bean("dataSource") public DataSourceProxy dataSourceProxy(DataSource dataSource) { return new DataSourceProxy(dataSource); } }
|
至此,Spring Cloud 整合 Seata 的基本完成,在事务发起方法上添加 @GlobalTransactional
注解即可
2.3 整合 Feign
分布式事务传播的过程中,需要通过判断事务id xid
来确认同一个事务。
Feign 默认使用线程池隔离,并且在发送请求时会丢弃父线程的请求头,导致 xid
无法正常传播。对此并没有必要改用信号量隔离,只需在过滤器中手动添加请求头即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class SeataXidFilter extends OncePerRequestFilter { protected Logger logger = LoggerFactory.getLogger(SeataXidFilter.class);
public static final String XID_HEADER = "Xid_Header";
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String xid = RootContext.getXID(); String restXid = request.getHeader(XID_HEADER); boolean bind = false; if (StringUtils.isBlank(xid) && StringUtils.isNotBlank(restXid)) { RootContext.bind(restXid); bind = true; if (logger.isDebugEnabled()) { logger.debug("bind[" + restXid + "] to RootContext"); } } try { filterChain.doFilter(request, response); } finally { if (bind) { String unbindXid = RootContext.unbind(); if (logger.isDebugEnabled()) { logger.debug("unbind[" + unbindXid + "] from RootContext"); } if (!restXid.equalsIgnoreCase(unbindXid)) { logger.warn("xid in change during http rest from " + restXid + " to " + unbindXid); if (unbindXid != null) { RootContext.bind(unbindXid); logger.warn("bind [" + unbindXid + "] back to RootContext"); } } } } } }
|
三、数据库脚本
在AT模式下需要创建 undo_log
,在上面的 file.conf
中已经做了配置,对此我们需要在数据库中创建 undo_log
回滚日志表。不同数据库的脚本略有差异,以 MySQL 为例:
1 2 3 4 5 6 7 8 9 10 11 12
| 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, PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
|
四、示例
官网中已经给了示例,自己做一个 AT 模式 SpringCloud版本的具体实现
仅供参考 无法作为实际业务逻辑