1、概念和历程
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
2、几种模式
2.1、术语
TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,驱动全局事务提交或回滚。
TM (Transaction Manager) - 事务管理器:定义全局事务的范围:开始全局事务、提交或回滚全局事务。
RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
2.2、AT 模式
前提:
- 基于支持本地 ACID 事务的关系型数据库。
- Java 应用,通过 JDBC 访问数据库。
整体机制:
- 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
二阶段:
- 提交异步化,非常快速地完成。
- 回滚通过一阶段的回滚日志进行反向补偿。
写隔离:
- 一阶段本地事务提交前,需要确保先拿到 全局锁 。
- 拿不到 全局锁 ,不能提交本地事务。
- 拿 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。
读隔离:
- 在数据库本地事务隔离级别 读已提交(Read Committed) 或以上的基础上,Seata(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted) 。
- 如果应用在特定场景下,必需要求全局的 读已提交 ,目前 Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。
工作机制:
- 一阶段--执行
- 二阶段--回滚
- 三阶段--提交
2.3、TCC 模式
回顾总览中的描述:一个分布式的全局事务,整体是 两阶段提交 的模型。全局事务是由若干分支事务组成的,分支事务要满足 两阶段提交 的模型要求,即需要每个分支事务都具备自己的:
- 一阶段 prepare 行为
- 二阶段 commit 或 rollback 行为
根据两阶段行为模式的不同,我们将分支事务划分为 Automatic (Branch) Transaction Mode 和 Manual (Branch) Transaction Mode。
AT 模式基于 支持本地 ACID 事务 的 关系型数据库:
- 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
- 二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
- 二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。
相应的,TCC 模式,不依赖于底层数据资源的事务支持:
- 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
- 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
- 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。
2.4、Saga 模式
Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。
适用场景:
- 业务流程长、业务流程多
- 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口
优势:
- 一阶段提交本地事务,无锁,高性能
- 事件驱动架构,参与者可异步执行,高吞吐
- 补偿服务易于实现
缺点:
- 不保证隔离性(应对方案见用户文档)
3、集成 IDEA
3.1、部分效果
数据库设计,4个微服务,3个数据库
下单前,没有订单信息,商品数量为100,金额为1000
下单成功,有订单信息,商品数量-1,金额-100
下单异常,uodo_log表记录异常信息
异常全部回滚
3.2、配置文件
seata配置文件,把file.conf和registry.conf粘贴到resource目录下。由于项目配置使用的是nacos管理:
bootstrap.yml文件:
spring:
application:
name: seata-bussiness-service # 注册到nacos上的服务名
profiles:
active: dev
cloud:
nacos:
# 注册中心
discovery:
username: nacos
password: nacos
server-addr: localhost:8848 #Nacos地址
namespace: 6d2e2958-3e7b-448b-8107-87ab6b022ba9
# 配置中心
config:
username: nacos
password: nacos
server-addr: localhost:8848 #Nacos地址
file-extension: yml #指定文件后缀,默认properties
namespace: 6d2e2958-3e7b-448b-8107-87ab6b022ba9
# 治理中心
sentinel:
transport:
dashboard: http://localhost:9555 #配置sentinel dashboard地址
port: 8719
alibaba:
seata:
tx-service-group: my_test_tx_group
#feign:
# sentinel:
# enabled: true #打开sentinel对feign的支持
seata事务核心依赖:
<!--seata事务依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<!--druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
3.3、测试 demo
为了更加准确模拟异常和分布式环境,所以使用4个微服务,同时操作不同数据库,产生异常后全部回滚。
这4个服务,配置文件和pom依赖基本都一样,只是注册到nacos上的服务名不同罢了,举例一下的bussiness业务服务的结构图:
3.3.1 seata-account 账户服务
AccountController.java 控制层:
package com.llh.controller;
import com.llh.domain.Account;
import com.llh.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* User: lilinhan
* DateTime: 2023/12/15 15:03
*/
@RestController
@RequestMapping("/account")
public class AccountController {
@Autowired
AccountService accountService;
@RequestMapping("/deduct")
public String deduct(){
// 扣钱
Account account = accountService.getById(1);
if(account!=null && account.getMoney()>=100){
account.setMoney(account.getMoney()-100);
accountService.updateById(account);
}
return "扣除成功";
}
}
3.3.2 seata-order 订单服务
OrderController.java 控制层:
package com.llh.controller;
import com.llh.api.AccountFeign;
import com.llh.domain.Order;
import com.llh.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* User: lilinhan
* DateTime: 2023/12/15 14:54
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
OrderService orderService;
@Autowired
AccountFeign accountFeign;
@RequestMapping("/porder")
public String porder(){
Order order = new Order();
order.setCount(1);
order.setCommodityCode("C1000");
order.setUserId("U1000");
order.setMoney(100);
// 1、下单
orderService.save(order);
//2、扣钱(RPC)
accountFeign.deduct();
return "下单成功";
}
}
AccountFeign.java 接口:
package com.llh.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* User: lilinhan
* DateTime: 2023/12/15 15:27
*/
@FeignClient(value = "seata-account-service",path = "account")
public interface AccountFeign {
@RequestMapping("/deduct")
public String deduct();
}
3.3.3 seata-storage 储存服务
StorageController.java 控制层:
package com.llh.controller;
import com.llh.domain.Storage;
import com.llh.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* User: lilinhan
* DateTime: 2023/12/15 14:46
*/
@RestController
@RequestMapping("/storage")
public class StorageController {
@Autowired
StorageService storageService;
@RequestMapping("/reduce")
// @GlobalTransactional(rollbackFor = Exception.class)//全局事务,有这个注解:TM
public String reduce(){
// 减库存
Storage storage = storageService.getById(1);
if(storage!=null && storage.getCount()>0){
storage.setCount(storage.getCount()-1);
storageService.updateById(storage);
}
return "扣减库存成功";
}
}
3.3.4 seata-bussiness 业务服务
BussinessController.java 控制层:
package com.llh.controller;
import com.llh.api.OrderFeign;
import com.llh.api.StorageFeign;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* User: lilinhan
* DateTime: 2023/12/15 15:52
*/
@RestController
@RequestMapping("/bussiness")
public class BussinessController {
@Autowired
OrderFeign orderFeign;
@Autowired
StorageFeign storageFeign;
@RequestMapping("/pay")
@GlobalTransactional(rollbackFor = Exception.class)//全局事务,有这个注解:TM
public String pay(){
storageFeign.reduce();
orderFeign.porder();
int i = 1/0;
return "支付成功";
}
}
OrderFeign.java 接口:
package com.llh.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* User: lilinhan
* DateTime: 2023/12/15 15:53
*/
@FeignClient(value = "seata-order-service",path = "order")
public interface OrderFeign {
@RequestMapping("/porder")
public String porder();
}
StorageFeign.java 接口:
package com.llh.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* User: lilinhan
* DateTime: 2023/12/15 15:53
*/
@FeignClient(value = "seata-storage-service",path = "storage")
public interface StorageFeign {
@RequestMapping("/reduce")
public String reduce();
}
3.3.5 uodo_log建表语句:
/*
Navicat Premium Data Transfer
Source Server : MySQL
Source Server Type : MySQL
Source Server Version : 80031 (8.0.31)
Source Host : localhost:3306
Source Schema : seata-storage
Target Server Type : MySQL
Target Server Version : 80031 (8.0.31)
File Encoding : 65001
Date: 16/12/2023 11:35:55
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log` (
`id` bigint NOT NULL AUTO_INCREMENT,
`branch_id` bigint NOT NULL,
`xid` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
`context` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `ux_undo_log`(`xid` ASC, `branch_id` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of undo_log
-- ----------------------------
SET FOREIGN_KEY_CHECKS = 1;
96 comments
光明守护者
内容的丰富性和深度让人仿佛置身于知识的海洋,受益匪浅。
对话设计自然,符合角色身份与情境。
情感真挚,直击人心,引发强烈共鸣。
情感真挚自然,字里行间传递出强烈的感染力。
这篇文章提供了宝贵的经验和见解,对读者有很大的启发和帮助。
若能对分论点进一步细分,结构会更立体。
这篇文章如同一幅色彩斑斓的画卷,每一笔都充满了独特的创意。
作者的布局谋篇匠心独运,让读者在阅读中享受到了思维的乐趣。
作者的观点新颖且实用,让人在阅读中获得了新的思考和灵感。
案例丰富且贴合主题,论证逻辑环环相扣。
作者的布局谋篇匠心独运,让读者在阅读中享受到了思维的乐趣。
情感真挚自然,字里行间传递出强烈的感染力。
若能在案例选择上更贴近现实,说服力会进一步提升。
首尾呼应,主题鲜明,收束有力。
?励志类评语?
哈哈哈,写的太好了https://www.lawjida.com/
哈哈哈,写的太好了https://www.lawjida.com/
哈哈哈,写的太好了https://www.lawjida.com/
《美狄亚的诅咒》恐怖片高清在线免费观看:https://www.jgz518.com/xingkong/36910.html