Seata是一款开源的分布式解决方案,提供高性能和简单易用的额分布式事务服务。提供了AT、TCC、SAGA和XA事务模式
Seata事务管理中三个重要的角色:
1.TC(Transaction Coordinate)-事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚
2.TM(Transition Manager)-事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务
3.RM(Resource Manager)-资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚
Seata提供四种不同的分布式事务解决方案:
XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入
TCC模式:最终一致的分阶段事务模式,有业务侵入
AT模式:最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式
SAGA模式:长事务模式,有业务侵入
解压Seata,修改registry.conf配置文件
1.选择自己要使用的配置中心(nacos)全部替换成nacos;
2.修改file.conf(存储模式)
Server的存储模式(mode)支持三种:
在数据库中创建数据库seata,,创建数据库表
- CREATE TABLE `branch_table` (
- `branch_id` bigint NOT NULL,
- `xid` varchar(128) NOT NULL,
- `transaction_id` bigint DEFAULT NULL,
- `resource_group_id` varchar(32) DEFAULT NULL,
- `resource_id` varchar(256) DEFAULT NULL,
- `branch_type` varchar(8) DEFAULT NULL,
- `status` tinyint 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=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
-
- CREATE TABLE `distributed_lock` (
- `lock_key` char(20) NOT NULL,
- `lock_value` varchar(20) NOT NULL,
- `expire` bigint DEFAULT NULL,
- PRIMARY KEY (`lock_key`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
-
- CREATE TABLE `global_table` (
- `xid` varchar(128) NOT NULL,
- `transaction_id` bigint DEFAULT NULL,
- `status` tinyint NOT NULL,
- `application_id` varchar(32) DEFAULT NULL,
- `transaction_service_group` varchar(32) DEFAULT NULL,
- `transaction_name` varchar(128) DEFAULT NULL,
- `timeout` int DEFAULT NULL,
- `begin_time` bigint DEFAULT NULL,
- `application_data` varchar(2000) DEFAULT NULL,
- `gmt_create` datetime DEFAULT NULL,
- `gmt_modified` datetime DEFAULT NULL,
- PRIMARY KEY (`xid`),
- KEY `idx_status_gmt_modified` (`status`,`gmt_modified`),
- KEY `idx_transaction_id` (`transaction_id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
-
- CREATE TABLE `lock_table` (
- `row_key` varchar(128) NOT NULL,
- `xid` varchar(128) DEFAULT NULL,
- `transaction_id` bigint DEFAULT NULL,
- `branch_id` bigint NOT NULL,
- `resource_id` varchar(256) DEFAULT NULL,
- `table_name` varchar(32) DEFAULT NULL,
- `pk` varchar(36) DEFAULT NULL,
- `status` tinyint NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
- `gmt_create` datetime DEFAULT NULL,
- `gmt_modified` datetime DEFAULT NULL,
- PRIMARY KEY (`row_key`),
- KEY `idx_status` (`status`),
- KEY `idx_branch_id` (`branch_id`),
- KEY `idx_xid` (`xid`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
修改script-config-center文件中的config.txt,同样将存储模式改为db,修改具体信息;配置自己分组service.vgroup_mapping.my_test_tx_group=default改为service.vgroup_mapping.自己=default
将配置文件配置到nacos,使用git
即配置成功!
下面进行模拟分布式事务:分别创建两个数据库(假设)-order订单数据库-money支付表数据库,即对应的订单表和支付表。分别创建两个项目:支付和订单
模拟之前一定要在两个数据库中加入undo_log表
- CREATE TABLE `undo_log` (
- `id` bigint NOT NULL AUTO_INCREMENT,
- `branch_id` bigint NOT NULL,
- `xid` varchar(100) NOT NULL,
- `context` varchar(128) NOT NULL,
- `rollback_info` longblob NOT NULL,
- `log_status` int 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=3 DEFAULT CHARSET=utf8mb3
支付模块
- server.port=8803
- spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
- spring.datasource.url= jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
- spring.datasource.username= root
- spring.datasource.password= 123456
- mybatis.configuration.map-underscore-to-camel-case= true
-
- spring.cloud.nacos.discovery.server-addr=localhost:8848
- spring.application.name=money
- spring.cloud.alibaba.seata.tx-service-group=guangzhou
-
- #配置seata的注册中心,告诉seata client 怎么去访问seata servellr
- seata.registry.type=nacos
- #可不配服务名
- seata.registry.nacos.application=seata-server
- seata.registry.nacos.server-addr= localhost:8848
- seata.registry.nacos.username=nacos
- seata.registry.nacos.password=nacos
- #seata server所在的分组,默认就是这个,没有可以不配
- seata.registry.nacos.group=SEATA_GROUP
-
- #配置seata的配置中心,
- seata.config.type=nacos
- seata.config.nacos.server-addr=localhost:8848
- seata.config.nacos.username=nacos
- seata.config.nacos.password=nacos
- @Mapper
- @Repository
- public interface MoneyMapper {
- public int subMoney();
- }
- @Service
- public class MoneyService {
- @Resource
- private MoneyMapper moneyMapper;
- public void subMoney(){
- moneyMapper.subMoney();
- }
- }
- @RestController
- public class MoneyController {
- @Resource
- MoneyService moneyService;
- @RequestMapping("/money")
- public String money(){
- moneyService.subMoney();
- return "支付成功";
- }
- }
- "1.0" encoding="UTF-8" ?>
- mapper
- PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.example.seatamoney.mapper.MoneyMapper">
- <update id="subMoney">
- update moneyTest set money=money-10 where id=1;
- update>
- mapper>
订单模块
- server.port=8180
- provider.ribbon.NFLoadBalancerRuleClassName:com.example.consumer.configuration.NacosWeightedRule
- spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
- spring.datasource.url= jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
- spring.datasource.username= root
- spring.datasource.password= 123456
- mybatis.mapper-locations= classpath:com/example/consumer/mapper/*.xml
- mybatis.configuration.map-underscore-to-camel-case= true
-
- spring.cloud.nacos.discovery.server-addr=localhost:8848
- spring.application.name=consumer
- spring.cloud.alibaba.seata.tx-service-group=guangzhou
-
-
- #配置seata的注册中心,告诉seata client 怎么去访问seata server
- seata.registry.type=nacos
- #可不配服务名
- seata.registry.nacos.application=seat-server
- seata.registry.nacos.server-addr= localhost:8848
- seata.registry.nacos.username=nacos
- seata.registry.nacos.password=nacos
- #seata server所在的分组,默认就是这个,没有可以不配
- seata.registry.nacos.group=SEATA_GROUP
-
- #配置seata的配置中心,
-
- seata.config.type=nacos
- seata.config.nacos.server-addr=localhost:8848
- seata.config.nacos.username=nacos
- seata.config.nacos.password=nacos
openFeign接口
- @Component
- @FeignClient(value = "money")
- public interface MoneyFeign {
- @RequestMapping("/money")
- public String money();
- }
- @Repository
- @Mapper
- public interface OrderMapper {
- public int addOrder();
- }
- "1.0" encoding="UTF-8" ?>
- mapper
- PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.example.consumer.mapper.OrderMapper">
- <update id="addOrder">
- update orders set num=num+1 where id=1;
- update>
- mapper>
- @Service
- public class OrderService {
- @Resource
- private OrderMapper orderMapper;
- public void addOrder(){
- orderMapper.addOrder();
- }
- }
- @RestController
- public class OrderController {
- @Resource
- OrderService orderService;
- @Resource
- MoneyFeign moneyFeign;
- @RequestMapping("/order")
- @GlobalTransactional
- public String Order(){
- moneyFeign.money();
- int i = 1/0;
-
- orderService.addOrder();
- return "下单成功";
- }
- }
- @SpringBootApplication
- @EnableFeignClients
- @MapperScan("com.example.consumer.mapper")
- public class ConsumerApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(ConsumerApplication.class, args);
- }
-
- }
如果Controller不加@GlobalTransitional注解,最后支付表-10元,但是订单表不变;
加上分布式事务后,两表都不发生变化