java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java Seata

Java分布式事务管理框架之Seata

作者:kaico2018

这篇文章主要介绍了Java分布式事务框架Seata,分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上

Seata介绍

Seata:Simple Extensible Autonomous Transaction Architecture,简易可扩展的自治式分布式事务管理框架,其前身是fescar。是一种简单分布式事务的解决方案。Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

官方文档:https://seata.io/zh-cn/docs/overview/what-is-seata.html

三大组件

事务协调器(TC):维护全局事务和分支事务的状态,驱动全局提交或回滚,相当于是协调者。

事务管理器(TM):定义全局事务的范围:开始全局事务,提交或回滚全局事务,相当于LCN中发起方。

资源管理器(RM):管理分支事务正在处理的资源,与TC进行对话以注册分支事务并报告分支事务的状态,并驱动分支事务的提交或回滚,相当于是LCN中的参与方

实现原理

四种事务模式

第一种、AT

使用这种模式有个前提:

实现过程分为两个阶段:

一阶段:

在一阶段中,Seata会拦截“业务SQL“,首先解析SQL语义,找到要更新的业务数据,在数据被更新前,保存下来"undo",然后执行”业务SQL“更新数据,更新之后再次保存数据”redo“,最后生成行锁,这些操作都在本地数据库事务内完成,这样保证了一阶段的原子性。

二阶段:

相对一阶段,二阶段比较简单,负责整体的回滚和提交,如果之前的一阶段中有本地事务没有通过,那么就执行全局回滚,否在执行全局提交,回滚用到的就是一阶段记录的"undo Log",通过回滚记录生成反向更新SQL并执行,以完成分支的回滚。当然事务完成后会释放所有资源和删除所有日志。

事务回滚的情况

事务提交的情况

**总结:**AT模式是一种无侵入的分布式事务解决方案,在 AT 模式下,用户只需关注自己的“业务 SQL”,用户的 “业务 SQL” 作为一阶段,Seata 框架会自动生成事务的二阶段提交和回滚操作。该模式会根据用户执行的SQL生成对应的回滚数据的SQL语句,然后根据事务的提交还是回滚来执行回滚的SQL语句还是删除对应的UNDO LOG 记录(SQL语句)。

第二种、TCC

不依赖于底层数据资源的事务支持:是指支持把 自定义 的分支事务纳入到全局事务的管理中。

一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
二阶段 commit 行为:调用 自定义 的 commit 逻辑。
二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。

第三种、Saga

Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。

第四种、XA

在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种事务模式。

使用前提:支持XA 事务的数据库。Java 应用,通过 JDBC 访问数据库。

这里主要介绍使用AT模式,后续提供每种模式的实现方式、代码案例。

搭建seata服务端

单机版安装

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

这里使用的是1.4.2版本

学习和测试建议使用单机版,简单搭建,生成环境不建议。

直接在github上下载对应的软件包,一键启动即可,默认是file模式,也就是数据以文件的形式保存本地。

解压之后,进入bin目录执行对应的启动命令即可:windows环境执行 bat文件,Linux环境执行 sh文件。

启动成功:

数据保存在本地

集群安装

首先准备mysql、nacos环境,在准备至少两台服务器,这里数据存到MySQL中去。

多个 Seata TC Server 通过 db 数据库,实现全局事务会话信息的共享。同时,每个 Seata TC Server 可以注册自己到注册中心上,方便应用从注册中心获得到他们。

初始化SQL语句(可以去github中找到,源码中也有),seata框架需要用的数据库表

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(128),
    `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;

每个seata服务节点的配置信息修改:主要修改下面两个文件

file.conf文件的修改:注意mysql 的版本,我这里使用的是MySQL8

store {
  ## store mode: file、db、redis
  mode = "db"
  ## rsa decryption public key
  publicKey = ""
  ## database store property
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.cj.jdbc.Driver"
    ## if using mysql to store the data, recommend add rewriteBatchedStatements=true in jdbc connection param
    url = "jdbc:mysql://www.kaicostudy.com:3306/transaction_seata?rewriteBatchedStatements=true"
    user = "root"
    password = "123456"
    minConn = 5
    maxConn = 100
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }
}

registry.conf 文件的修改:

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"

  nacos {
    application = "seata-server"
    serverAddr = "www.kaicostudy.com:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = ""
    password = ""
  }
}

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "www.kaicostudy.com:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = ""
    password = ""
    dataId = "seataServer.properties"
  }
}

修改好每个seata服务节点的配置信息后,正常一次启动seata服务就可以了。之后可以在nacos看到seata服务的信息。

到此这篇关于Java分布式事务管理框架之Seata的文章就介绍到这了,更多相关Java Seata内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文