seata操作文档
1. 前言
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式。
2. 术语
- TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。 - TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。 - RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
说明:TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成。
3. server端
3-1. 下载安装包
下载地址:https://github.com/seata/seata/releases
注意:取最新分支安装包
3-2. 事物日志
store mode: file、db
file模式配置项:默认
db模式配置项:
- 初始化数据库信息:https://github.com/seata/seata/blob/1.2.0/script/server/db/mysql.sql(最新分支)
- 数据库地址及数据库名称
- 用户名/密码
说明:高可用部署方案需要使用DB模式共享全局事务会话信息。
3-3. 注册中心
注册中心:file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
eg:
eureka {
serviceUrl = "http://用户名:密码@IP:port/eureka" # 注册中心地址
application = "idaas-seata-server" # 注册应用名称
weight = "1" # 权重
}
说明:高可用部署方案需要注册中心使用非file的seata支持的第三方注册中心。
3-4. 配置中心
配置中心:file、nacos 、apollo、zk、consul、etcd3
eg:
zk {
serverAddr = "127.0.0.1:2181"
session.timeout = 6000
connect.timeout = 2000
}
3-5. 启动
- 完成好上述配置
- 启动
Usage: sh seata-server.sh(for linux and mac) or cmd seata-server.bat(for windows) [options]
Options:
--host, -h
The host to bind.
Default: 0.0.0.0
--port, -p
The port to listen.
Default: 8091
--storeMode, -m
log store mode : file、db
Default: file
--help
e.g.
sh seata-server.sh -p 8091 -h 127.0.0.1 -m db &
注意:如果linux启动服务后需要设置在后台运行,堆内存建议分配2G,堆外内存1GE
4. client端
客户端选择springcloud微服务框架
4-1. 依赖
引入依赖:
<!-- spring-cloud-alibaba-seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-seata</artifactId>
<version>${spring-cloud-alibaba-seata.version}</version>
<!-- 如果内嵌最新版本starter,我们不用排除再引入 -->
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 最新版本seata-spring-boot-starter -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>${seata.version}</version>
</dependency>
4-2. 创建 UNDO_LOG 表
AT 模式需要 UNDO_LOG 表
-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
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;
说明:表名可自定义
4-3. 添加seata 配置
使用yml风格,下为基础配置,如需更多配置请查询官网
# -----------seata常用配置,如需修改请参考使用文档--------------
seata:
enabled: true
application-id: ${spring.application.name} #服务名
tx-service-group: default # default是自定义的事务分组名称
enable-auto-data-source-proxy: true # 启用自动数据源代理
use-jdk-proxy: false
service:
vgroup-mapping:
default: idaas-seata-server # default是自定义的事务分组名称,idaas-seata-server是tc注册到注册中心的服务名称
enable-degrade: false # 是否启用降级
disable-global-transaction: false # 是否禁用全局事务
config:
type: file # 配置中心(consul、apollo、etcd3、nacos、zk、file)
registry:
type: eureka # 注册中心(consul、etcd3、eureka、nacos、redis、sofa、zk)
eureka:
weight: 1
service-url: ${eureka.client.service-url.defaultZone} # 注册中心地址
client:
undo:
log-table: idaas_seata_undo_log # 自定义undo_log表名
说明:enable-auto-data-source-proxy 可能会与mybatis-plus冲突,如果冲突不能删除undolog,则设置enable-auto-data-source-proxy为false
4-4. 配置数据源
@Configuration
public class DataSourceProxyConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return new DruidDataSource();
}
@Bean
public DataSourceProxy dataSourceProxy(DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean
public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSourceProxy);
return sqlSessionFactoryBean.getObject();
}
}
Hikari 数据源更改DataSource
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public DataSource dataSource() {
return new HikariDataSource();
}
4-5. 开启事务
- 事物起点使用注解:@GlobalTransactional(rollbackFor = Exception.class)
- 微服务事物正常使用注解:@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
在业务的发起方的方法上使用@GlobalTransactional
开启全局事务,Seata 会将事务的 xid 通过拦截器添加到调用其他服务的请求中,实现分布式事务
4-6. 多数据源下使用seata
@Configuration
public class DataSourceProxyConfig {
@Bean("originOrder")
@ConfigurationProperties(prefix = "spring.datasource.order")
public DataSource dataSourceMaster() {
return new DruidDataSource();
}
@Bean("originStorage")
@ConfigurationProperties(prefix = "spring.datasource.storage")
public DataSource dataSourceStorage() {
return new DruidDataSource();
}
@Bean("originPay")
@ConfigurationProperties(prefix = "spring.datasource.pay")
public DataSource dataSourcePay() {
return new DruidDataSource();
}
@Bean(name = "order")
public DataSourceProxy masterDataSourceProxy(@Qualifier("originOrder") DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean(name = "storage")
public DataSourceProxy storageDataSourceProxy(@Qualifier("originStorage") DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean(name = "pay")
public DataSourceProxy payDataSourceProxy(@Qualifier("originPay") DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean("dynamicDataSource")
public DataSource dynamicDataSource(@Qualifier("order") DataSource dataSourceOrder,
@Qualifier("storage") DataSource dataSourceStorage,
@Qualifier("pay") DataSource dataSourcePay) {
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
Map<Object, Object> dataSourceMap = new HashMap<>(3);
dataSourceMap.put(DataSourceKey.ORDER.name(), dataSourceOrder);
dataSourceMap.put(DataSourceKey.STORAGE.name(), dataSourceStorage);
dataSourceMap.put(DataSourceKey.PAY.name(), dataSourcePay);
dynamicRoutingDataSource.setDefaultTargetDataSource(dataSourceOrder);
dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);
DynamicDataSourceContextHolder.getDataSourceKeys().addAll(dataSourceMap.keySet());
return dynamicRoutingDataSource;
}
@Bean
@ConfigurationProperties(prefix = "mybatis")
public MybatisSqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("dynamicDataSource") DataSource dataSource) {
// 这里用 MybatisSqlSessionFactoryBean 代替了 SqlSessionFactoryBean,否则 MyBatisPlus 不会生效
MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
mybatisSqlSessionFactoryBean.setDataSource(dataSource);
return mybatisSqlSessionFactoryBean;
}
}