5.springcloudAlibaba-Seata 分布式事务

1.springcloudAlibaba-nacos

2.springcloudAlibaba-openFeign

3.springcloudAlibaba-负载均衡器Ribbon

4.springcloudAlibaba-nacos配置中心

5.springcloudAlibaba-Seata 分布式事务

6.springcloudAlibaba-sentinel

7.springcloudAlibaba-网关gateway


目录

事务

Seata是什么

常见分布式事务解决方案

分布式事务理论基础

AT模式(auto transcation)

TCC 模式

Seata搭建

Seata的三大角色

 Seata Server(TC)环境搭建

配置server

创建数据库seata

配置nacos config

启动Seata Server

配置客户端

配置客户端seata


事务

     事务(Transaction) 是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。在关系数据

库中,一个事务由一组SQL语句组成。事务应该具有4个属性:原子性、一致性、隔离性、持久性。

这四个属性通常称为ACID特性。

     原子性(atomicity):个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么

都不做。

     一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态,事务

的中间状态不能被观察到的。

     隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数

据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。隔离性又分为四个级别:读

未提交(read uncommitted)、读已提交(read committed,解决脏读)、可重复读(repeatable

read,解决虚读)、串行化(serializable,解决幻读)。

    持久性(durability):持久性也称永久性(permanence),指一个事务一旦提交,它对数据库

中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

    任何事务机制在实现时,都应该考虑事务的ACID特性,包括:本地事务、分布式事务,及时不能

都很好的满足,也要考虑支持到什么程度

通常本地事务@Transational 基本就足够了,但是在分布式环境中 同一个方法中 可能调用不同的数据库或者调用不同的服务 服务再调用数据库 @Transational 明显就不能保证

Seata是什么

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。AT模式是阿里首推的模式,阿里云上有商用版本的GTS(Global Transaction Service 全局事务服务)

官网:Seata

源码: GitHub - seata/seata: Seata is an easy-to-use, high-performance, open source distributed transaction solution.

官方Demo: GitHub - seata/seata-samples: seata-samples

常见分布式事务解决方案

1、seata 阿里分布式事务框架

2、消息队列

3、saga

4、XA

他们有一个共同点,都是“两阶段(2PC)”。“两阶段”是指完成整个分布式事务,划分成两个步骤

完成。

实际上,这四种常见的分布式事务解决方案,分别对应着分布式事务的四种模式:AT、TCC、Saga、XA;

四种分布式事务模式,都有各自的理论基础,分别在不同的时间被提出;每种模式都有它的适用场

景,同样每个模式也都诞生有各自的代表产品;而这些代表产品,可能就是我们常见的(全局事务、

基于可靠消息、最大努力通知、TCC)

分布式事务理论基础

解决分布式事务,也有相应的规范和协议。分布式事务相关的协议有2PC、3PC。

由于三阶段提交协议3PC非常难实现,目前市面主流的分布式事务解决方案都是2PC协议

2PC两阶段提交协议:Prepare 和 Comm

AT模式(auto transcation)

主要是在项目中引入了 中间协调人

prepare:预执行

通过协调者向各个服务发送事务请求,查看是否可用执行,各个服务接收到请求后 执行对应操作 并将状态修改信息保存日志中 将相应结果返回给 协调者

在一阶段,Seata 会拦截“业务 SQL”,首先解析 SQL 语义,找到“业务 SQL”要更新的业务数

据,在业务数据被更新前,将其保存成“before image”,然后执行“业务 SQL”更新业务数据,

在业务数据更新之后,再将其保存成“after image”,最后生成行锁。以上操作全部在一个数据库

事务内完成,这样保证了一阶段操作的原子性

Commit:执行事务提交

执行事务提交分为两种情况,正常提交和回退

二阶段如果是提交的话,因为“业务 SQL”在一阶段已经提交至数据库, 所以 Seata 框架只需将一

阶段保存的快照数据和行锁删掉,完成数据清理即可。

二阶段如果是回滚的话,Seata 就需要回滚一阶段已经执行的“业务 SQL”,还原业务数据。回滚方

式便是用“before image”还原业务数据;但在还原前要首先要校验脏写,对比“数据库当前业务

数据”和 “after image”,如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一

致就说明有脏写,出现脏写就需要转人工处理。

在执行 Prepare 步骤过程中,如果某些参与者执行事务失败、宕机或与协调者之间的网络中断,那么协调者就无法收到所有参与者的 YES 响应,或者某个参与者返回了 No 响应,此时,协调者就会进入回退流程,对事务进行回退。

AT 模式的一阶段、二阶段提交和回滚均由 Seata 框架自动生成,用户只需编写“业务 SQL”,便能

轻松接入分布式事务,AT 模式是一种对业务无任何侵入的分布式事务解决方案

TCC 模式

1. 侵入性比较强, 并且得自己实现相关事务控制逻辑
2.在整个过程基本没有锁,性能更强
TCC 模式需要用户根据自己的业务场景实现 Try、Confirm 和 Cancel 三个操作;事务发起方在一阶
段执行 Try 方式,在二阶段提交执行 Confirm 方法,二阶段回滚执行 Cancel 方法

Seata搭建

Seata的三大角色

在 Seata 的架构中,一共有三个角色:

TC (Transaction Coordinator) - 事务协调者

维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器

定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM (Resource Manager) - 资源管理器

管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

其中,TC 为单独部署的 Server 服务端,TM 和 RM 为嵌入到应用中的 Client 客户端。

 Seata Server(TC)环境搭建

配置server

seata 的环境搭建很麻烦,但是一旦搭建起来后面使用就是一个注解的事,所以这部分搭建要有耐心

下载安装包 根据版本对应 选择1.3.0 的版本

Tags · seata/seata · GitHub

下载seata-server-1.3.0.tar.gz 解压 tar -zxvf

打开config/file.conf   

修改mode="db"

修改数据库连接信息

这里file 不配也可以,后面配置到nacos config里

修改seata/conf 下registry.conf 配置nacos信息 一个注册 一个config

创建数据库seata

新建表:

GitHub - seata/seata: Seata is an easy-to-use, high-performance, open source distributed transaction solution.

下载code找到db 创建数据库 seata 这里我用的mysql 执行mysql.sql 创建三张表

配置nacos config

在下载的code中找到 script ,将script放到seata目录下

修改seata/script/config-center 下config.txt

找到seata/script/config-center/nacos 下nacos-config.sh 执行

 sh nacos-config.sh -h nacosip -p 8848 -g SEATA_GROUP -t 命名空间 -u username -w password

登录nacos 控制台 看到多了很多seata配置文件证明执行成功

启动Seata Server

然后启动seata

cd /usr/local/seata/bin 
sh seata-server.sh -h 49.232.193.91 -p 8091 -m db 

-h: 注册到注册中心的ip 这里注意如果 项目不在一个服务器 尽量使用外网ip 否则服务端可能会访问不到

-p: Server rpc 监听端口

-m: 全局事务会话信息存储模式,file、db、redis,优先读取启动参数 (Seata-Server 1.3及以上版本支持redis)

-n: Server node,多个Server时,需区分各自节点,用于生成不同区间的transactionId,以免冲突

-e: 多环境配置参考 http://seata.io/en-us/docs/ops/multi-configuration-isolation.html


如果要搭建集群的话

在nacos 服务列表可以看到 有seata-server 服务

配置客户端

新建两个个springcloud module seata-order /seata-store

配置 数据库 datasource nacos openFeign 这里就不细说了

创建两个表 order /store num 都给 10

然后在两个module中简单写两个sql

在seata-order service 中 先调用本地sql 再通过openFeign调用seata-store 中的sql

@Service
public class OrderSeataService {
    @Resource(name = "daoSupport")
    private DaoSupport dao;
    
    @Autowired
    StoreSeataService storeSeataService;
    
    public void updateOrder() throws Exception {
        dao.update("OrderMapper.updateOrder", null);
    }
    
    @Transactional
    public void updateOrderNum() throws Exception {
        
        updateOrder();
        storeSeataService.updateOrderNum();
        int  i=1/0;
    }
}

/**
 * @author LZQ
 * @create 2022-07-31 8:57
 * @desc
 **/
@Service
@FeignClient(value = "seata-store", path = "/seataStore")
public interface StoreSeataService {

    @RequestMapping("/updateStoreNum")
    String updateOrderNum();
}
@RestController
@RequestMapping(value = "/seataStore")
public class SeataStoreController {

//@Autowired
//OrderService orderService;

@Autowired
StoreSeataService storeService;


    @RequestMapping(value = "/updateStoreNum")
    public void getUserInfo() throws Exception {
        storeService.updateOrder();
//        System.out.println("Seata全局事务id=================>{}"+ RootContext.getXID());
    }

}

在OrderSeataService 中updateOrderNum 方法上加入@Transactional 注解

调用此方法发现

本地事务回滚了,但是seata-store 并没有,所以@Transactional 注解 只能进行本地的回滚

配置客户端seata

在数据库中增加 事务的日志表 如果是多个数据库 在服务的数据库中都要加

-- 注意此处0.7.0+ 增加字段 context
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;

增加seata依赖

     <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        </dependency>

增加配置文件

  cloud:
    alibaba:
      seata:
        tx-service-group: default_tx_group
seata:
  registry:
    # 配置seata的注册中心,告诉seata clent 怎么去访问server
    type: nacos
    nacos:
      application: seata-server
      server-addr: 49.232.193.91:8848
      username: nacos
      password: nacos
      group: SEATA_GROUP #seata 默认分组
      namespace: 40733d09-019d-4d59-9ab0-823f3058beab
  config:
    type: nacos
    nacos:
      server-addr: 49.232.193.91:8848
      username: nacos
      password: nacos
      group: SEATA_GROUP
      namespace: 40733d09-019d-4d59-9ab0-823f3058beab

其中 tx-service-group: default_tx_group 是上传配置文件中 事务服务分组 很多配置失败都是这里没写正确

总的配置文件

server:
  port: 6666
spring:
  application:
    name: seata-order
  cloud:
    nacos:
      server-addr: 49.232.193.91:8848
      discovery:
        username: nacos
        password: nacos
        namespace: 40733d09-019d-4d59-9ab0-823f3058beab
    alibaba:
      seata:
        tx-service-group: default_tx_group
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    name: defaultDataSource
    url: jdbc:mysql://49.232.193.91:3306/seata?serverTimezone=UTC&characterEncoding=utf-8&useSSL=false
    username: seata
    password: seata
ribbon:
  eureka:
    enabled: false
seata:
  registry:
    # 配置seata的注册中心,告诉seata clent 怎么去访问server
    type: nacos
    nacos:
      application: seata-server
      server-addr: 49.232.193.91:8848
      username: nacos
      password: nacos
      group: SEATA_GROUP
      namespace: 40733d09-019d-4d59-9ab0-823f3058beab
  config:
    type: nacos
    nacos:
      server-addr: 49.232.193.91:8848
      username: nacos
      password: nacos
      group: SEATA_GROUP
      namespace: 40733d09-019d-4d59-9ab0-823f3058beab

seata-store 跟seata-order 都要配

配置完成后在方法上加入@GlobalTransactional 注解

//    @Transactional
@GlobalTransactional
public void updateOrderNum() throws Exception {
    updateOrder();
    storeSeataService.updateOrderNum();
    int  i=1/0;
    }

然后重新调用方法

可以看到数据库都回滚了 然后再看日志 seata 确实执行了回滚

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毛利小伍琪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值