简介
分布式事务解决方案seata的相关基本概念,环境的搭建和使用
基本概念
事务,一组不可分割的操作,要么全部成功,要么全部失败。有ACID四大特性。
事务分为:本地事务和分布式事务。
本地事务:程序操作一个数据库的时候,这时的事务就是本地事务,可以使用@Transaction来保证。
分布式事务:操作多个不同节点的数据库,或者是多个服务的操作,这时的事务就是分布式事务。
seata
是一款分布式事务解决方案。提供了AT,TCC,SAGA,和XA事务模式。一般常用的是AT模式。
常见的分布式事务解决方案:
- seata
- 消息队列
- saga
- xa
一般常见的分布式事务解决方案都是两阶段提交协议的(2PC)
两阶段提交:prepare,commit
prepare:预处理阶段
commit:提交/回滚阶段
AT模式
是一种无侵入的分布式事务解决方案,也是二阶段提交的。
第一阶段:seata会去拦截sql语句,会先去查询这条sql要操作的数据,保存成before image,执行sql,将更新后的数据保存为after image,给这条数据生成行锁。
第二阶段提交:删除掉保存的数据快照(before/after image)和行锁。
第二阶段回滚:先校验是否有脏写,即对比数据库的数据和after image中的是否一致,如果有脏写,需要人工处理;如果没有脏写,使用after image还原数据。
TCC模式
需要使用者在自己的业务代码中实现Try(事务发起),Confirm(提交),Cancel(回滚)操作。
和AT模式对比:
- 侵入性比较强
- 性能更好,因为整个过程中,基本没有使用锁。
- 更灵活
seata架构中的三大角色:
- TC:事务协调者,维护全局和分支事务的状态,驱动全局事务提交或回滚
- TM:事务管理器,定义全局事务的范围,开始,提交,回滚全局事务
- RM:资源管理器,管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚
seata的工作原理
- TM请求TC开启全局事务,TC生成一个XID,会在微服务的调用链中传播,保证多个微服务的子事务关联在一起
- RM请求TC将本地事务注册为全局事务的分支事务,通过XID关联
- TM请求TC告诉关于XID对应的全局事务是提交还是回滚
- TC驱动RRM将XID对应的本地事务进行提交或回滚
TC一般会作为一个独立的服务部署。
TM和RM是在业务代码(客户端)中使用注解,seata会自动的去维护。
seata的使用
db+nacos的方式部署高可用集群模式
seata服务端(TC)的搭建
下载seata的服务端:seata官网下载地址
我下载的是Windows版本的1.3.0
下载解压之后,还需要进行相关的配置
seata端存储模式有三种:
- file(默认模式),单机模式,全局事务会话信息内存中读写并持久化本地文件root.data,性能高
- db,高可用模式,全局事务会话信息通过db共享,性能较差
- redis,性能高,事务信息有丢失风险
修改seata service的存储模式为db
修改file.conf文件
把mode = "file"
修改成mode = “db”
修改mysql的配置信息
在mysql数据库中创建相关的表
CREATE TABLE IF NOT EXISTS `global_table`
(
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`status` TINYINT NOT NULL,
`application_id` VARCHAR(32),
`transaction_service_group` VARCHAR(32),
`transaction_name` VARCHAR(128),
`timeout` INT,
`begin_time` BIGINT,
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`xid`),
KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256),
`branch_type` VARCHAR(8),
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME(6),
`gmt_modified` DATETIME(6),
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(96),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
设置nacos注册中心
修改registry.conf文件
把registr中的type = "file"
修改为type = "nacos"
修改nacos的相关配置
`
设置nacos配置中心
也是修改registry.conf文件
把config中的type = "file"
修改为type = "nacos"
修改nacos作为配置中心的相关配置
下载源码
可以在github官网中下载这个源码。里面有默认的配置信息。
把上图中的script文件复制一份放到seata文件夹(之前下载的seata service)中
修改config.txt
修改script中的config.txt,把store.mode=file
改成store.mode=db
删除掉红框中的内容
修改数据库的配置信息
运行nacos-config.sh脚本
运行脚本,可以把config.txt里面的默认内容注册到nacos配置中心中去了。
服务中整合seata
pom文件中添加依赖
<!--seata的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
在微服务的数据库中新增一个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,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
修改application.yml配置文件
给当前服务配置访问seata service(TC)
seata:
registry:
# 配置seata的注册中心
type: nacos
nacos:
server-addr: 127.0.0.1:8848
application: seata-server
config:
# 配置seata的配置中心
type: nacos
nacos:
server-addr: 127.0.0.1:8848
修改启动类
添加@EnableTransactionManagement 注解和@EnableGlobalTransaction注解
@SpringBootApplication
@EnableTransactionManagement
@EnableGlobalTransaction
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
业务代码添加@GlobalTransaction注解
只需要在要使用分布式事务的方法上添加@GlobalTransaction注解
即可使用。
@GlobalTransactional
public Order create(Order order) {
orderMapper.insert(order);
stockService.reduct(order.getProductId());
int a=1/0;
return order;
}
seata主要是环境的配置很负载,使用的话只需要添加注解即可