分布式解决方案之Seata

本文详细介绍了事务的概念,包括本地事务的ACID特性,以及如何通过数据库和JDBC进行事务控制。接着重点讲解了分布式事务,强调在不同服务间保持事务的一致性需求,并以Seata为例,阐述了分布式事务的四种模式,特别是AT模式的工作流程。Seata作为一套分布式事务解决方案,由TM、RM和TC组成,提供了无业务侵入的AT模式,确保高可用性和一致性。文章还涵盖了Seata的安装和配置,以及其核心组件和数据存储方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

事务的介绍

一、什么是本地事务?

当你需要一次执行多条事务的时候。通俗一点说就是如果这几条sql全部执行成功 或者全部执行失败,全部回滚保持原子性。想要达到这种效果就需要事务来进行控制。

回顾一下数据库事务的四大特性(ACID):

  • 原子性(Atomicity):要么都执行要么都不执行
  • 一致性(Consistency):事务前后的的数据都是正确的
  • 隔离性(Isolation):事务之前互相隔离,互不干扰(并发执行事务的时候看不见彼此的状态)
  • 持久性(Durability):事务一旦提交不能回滚

二、本地事务控制

举个例子:Mysql数据库的InnoDB存储引擎支持事务。mysql数据库又和应用存储在同一台服务器上,此时就称为本地事务。

1.数据库本身进行事务控制
begin transaction;
      //1.本地数据库操作:保存订单
      //2.本地数据库操作:扣减库存
rollback;
或
commit transaction;
2.JDBC进行控制事务
  1. 获取对数据库的连接
  2. 设置数据库不自动提交
conn.setAutoCommit(false);   //其中conn是第一步获取的随数据库的连接对象。
  1. 把想要控制的sql使用事务进行提交
try{
    Statement stmt = null; 
    stmt =conn.createStatement(); 
    stmt.executeUpdate(sql1); 
    int a=6/0;
    stmt.executeUpdate(Sql2); 
    . 
    conn.commit();   //使用commit提交事务 
}
  1. 捕获异常,进行数据回滚
catchException e) { 
   ... 
   conn.rollback(); 
}
AOP进行控制事务
@Transactional //mybatis的注解
begin tran
public void insertOrder(TbOrder tbOrder) {
    //1、保存订单
    tbOrderMapper.insertSelective(tbOrder);

    //2、扣减库存
    itemServiceFeign.updateItem(tbOrder.getItemId(), tbOrder.getNum());
}
commit/rollback

三、分布式事务 (重点)

分布式事务总而言之就是一句,在服务中调用另外一个服务(不在同一个模块甚至不是同一个应用),还可以做到多个sql保持ACID属性

举例:

@Transactional
@Override
public void insertOrder(TbOrder tbOrder) {
    //1、保存订单
    tbOrderMapper.insertSelective(tbOrder);

    //2、扣减库存
    itemServiceFeign.updateItem(tbOrder.getItemId(), tbOrder.getNum());

    //模拟扣款失败,此时扣减库存会回滚吗?
    int a = 6/0;
}

此时如果不进行分布式事务控制,扣减的库存是不会回滚的。

但是分布式事务的应用场景并不是只有这一种,跨数据库,跨服务,两个服务使用同一个数据库也是需要分布式事务进行控制的

所以就需要分布式事务开加以控制。

最为简单的分布式事务解决方案Seata

一、Seata的介绍

这个玩意儿呢是阿里中间件团队发起的开源项目Fescar(Fast & EaSy Commit And Rollback)后来改名成 Seata (Simple Extensible Autonomous Transaction Architecture),就是一套分布式解决方案。

官网放在这里:http://seata.io/zh-cn/

二、Seata的分布式事务解决方案

Seata提供了四种不同的分布式事务解决方案:

  • **XA模式:**强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入.
  • **TCC模式:**最终一致的分阶段事务模式,有业务侵入
  • **AT(auto transaction)模式:**最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式.
  • **SAGA模式:**长事务模式,有业务侵入

这四种模式我们最常用的就是AT模式,也是默认模式。为什么用它,虽然可靠消息最终一致性最后也能达到一致性,但是为什么不用呢?那你思考一下,当你给你的好妹妹转账的时候,你上午都转了,晚上了都好妹妹都跑路了,钱还没转到,这合适吗。。。

所以说此时我们需要强制一致性,要很快的能够得到结果。扯远了啊,AT模式主要是因为无业务侵入,就很干净,还有可用性的存在。所以那就用它

三、Seata的核心组件

Seata事务管理有三个重要的核心组件(TM和他儿子们RMs与管家TC的故事)

在这里插入图片描述

其中5不一定会进行。如果都成功了还回滚啥回滚、
**注意:**第2步中,RM是已经将事务提交了的。所以第4步的提交只是确认一下。

都提交了为啥还能回滚呢?这就要说一下他的机制了。

四、AT模式的工作流程

一阶段

在这里插入图片描述
看图上的介绍,其中业务DB的中业务的旁边存在一个Log表,在事务开始时会将原快照(前镜像),执行sql包括sql之后的新快照(后镜像)都存放到Log表中。

在这里插入图片描述

表中的字段看上图

  1. 注册分支事务
    RM向TC注册分支事务将其其纳入XID对应全局事务的管辖,并申请 product 表中主键值等于 1 的记录的全局锁 。

  2. 本地事务提交
    业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交。

  3. 上报事务状态
    将本地事务提交的结果上报给 TC。

到此为止一阶段就算完成了

二阶段 - 回滚

在这里插入图片描述
(1)收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作。

(2)通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。

(3)数据校验

拿 UNDO LOG 中的后镜与当前数据进行比较,根据校验结果决定是否做回滚。

(4)根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句:

update product set name = 'TXC' where id = 1;

(5)提交本地事务

并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。

二阶段 - 提交

在这里插入图片描述
第二阶段全局事务提交,TC会通知各各分支参与者提交分支事务,在第一阶段就已经提交了分支事务,这里各各参与者只需要删除undo_log即可,并且可以异步执行,第二阶段很快可以完成。所以一阶段的RM是提交了事务的。

Seata安装和启动

一、下载地址

下载地址:https://github.com/seata/seata/releases

二、安装

  1. 上传并解压安装包:
[root@localhost ~]# cd /usr/upload
[root@localhost upload]# tar -zxvf seata-server-1.4.2.tar.gz -C /usr/local	
  1. 修改seata/seata-server-1.4.2/conf/目录下的registry.conf文件:
registry {
  #tc服务的注册中心类型,这里选择nacos,也可以是eureka、zookeeper等
  type = "nacos"

  nacos {
    # seata tc服务注册到nacos的服务名称,可以自定义
    application = "seata-server"
    # nacos的地址
    serverAddr = "192.168.112.133:8848"
    # seata服务所在分组
    group = "DEFAULT_GROUP"
    # seata服务所在的名称空间,这里不填就是使用默认的"public"
    namespace = ""
    # TC集群名,默认是"default"
    cluster = "default"
    # 这个是nacos的用户名
    username = ""
    # 这个是nacos的密码
    password = ""
  }
}
config {
  # tc服务的配置中心类型:file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "192.168.112.133:8848"
    namespace = ""
    group = "DEFAULT_GROUP"
    username = ""
    password = ""
    dataId = "seataServer.properties"
  }
}  
  1. 在Nacos中添加配置信息
    配置信息地址:https://gitee.com/seata-io/seata/blob/develop/script/config-center/config.txt

**划重点:**只需要看上面和数据库连接的内容,其他的玩意儿如果你需要改也不用来看这个文档了

# 数据存储方式,db代表数据库
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://192.168.112.137:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=root
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
# 事务、日志等配置
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000

# 客户端与服务端传输方式
transport.serialization=seata
transport.compressor=none
# 关闭metrics功能,提高性能
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

启动成功了效果如下:
在这里插入图片描述

三、创建TC服务数据表

  1. 建库
    在这里插入图片描述
  2. 建表
    建表语句地址:https://gitee.com/seata-io/seata/blob/develop/script/server/db/mysql.sql
-- -------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
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;

CV这一个也是可以。

四、启动Seata

  1. 启动
[root@localhost local]# cd seata/bin
[root@localhost bin]# ./seata-server.sh
#或
[root@localhost bin]# ./seata-server.sh -h 192.168.112.133 -p 8091
... ...
io.seata.config.FileConfiguration        : The configuration file used is /usr/local/seata/seata-server-1.4.2/conf/registry.conf
 com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited
i.s.core.rpc.netty.NettyServerBootstrap  : Server started, listen port: 8091
  1. 测试seata是否注册成功
    在这里插入图片描述

注意测试的时候注意一下IP地址!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值