seata实现2PC事务
发布日期:2021-05-06 15:30:24 浏览次数:24 分类:精选文章

本文共 6953 字,大约阅读时间需要 23 分钟。

Seata分布式事务示例

本示例通过Seata中间件实现分布式事务,模拟三个账户的转账交易过程。两个账户在三个不同的银行(张三在bank1、李四在bank2),bank1和bank2是两个微服务。交易过程是,张三给李四转账指定金额。


业务说明

交易过程是:

  • 张三将转账金额减少到账户中
  • bank1调用bank2,将转账金额增加到李四的账户中

  • 交互流程

  • bank1接收转账请求,传入转账金额
  • bank1减少转账金额,调用bank2,传入转账金额
  • bank2增加转账金额

  • 数据库创建

    seata-bank1库

    -- 账户表
    CREATE TABLE `account_info` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `account_name` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '户主姓名',
    `account_no` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '银行卡号',
    `account_password` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '帐户密码',
    `account_balance` double DEFAULT NULL COMMENT '帐户余额',
    PRIMARY KEY (`id`) USING BTREE
    );
    -- Seata框架需要使用的表
    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,
    `ext` varchar(100) DEFAULT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=167 DEFAULT CHARSET=utf8;

    seata-bank2库

    -- 账户表
    CREATE TABLE `account_info` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `account_name` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '户主姓名',
    `account_no` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '银行卡号',
    `account_password` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '帐户密码',
    `account_balance` double DEFAULT NULL COMMENT '帐户余额',
    PRIMARY KEY (`id`) USING BTREE
    );
    -- Seata框架需要使用的表
    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,
    `ext` varchar(100) DEFAULT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=167 DEFAULT CHARSET=utf8;

    启动TC(事务协调器)

  • 下载Seata服务器(版本是0.7.1)

  • 微服务相关版本说明

    • Spring Boot:2.1.12.RELEASE
    • Spring Cloud Alibaba:2.1.0.RELEASE
    • Spring Cloud Greenwich.SR6
  • 启动Seata服务器 -进入D:\seata-server-0.7.1\bin目录 -命令:seata-server.bat -p 8888 -m file


  • 环境配置

    • Nacos:1.3.1
    • Maven:3.5.2
    • Seata:0.7.1
    • Spring Boot:2.1.12.RELEASE
    • Spring Cloud Alibaba:2.1.0.RELEASE
    • Spring Cloud Greenwich.SR6

    Seata父模块代码结构

    4.0.0
    com.seata
    seata-parent
    pom
    1.0-SNAPSHOT
    ../seata-bank1
    ../seata-bank2
    ../seata-common
    org.springframework.boot
    spring-boot-starter-parent
    2.1.12.RELEASE
    UTF-8
    UTF-8
    1.8
    1.8
    1.8
    2.1.0.RELEASE
    com.alibaba.cloud
    spring-cloud-alibaba-dependencies
    ${spring-cloud-alibaba.version}
    pom
    import
    org.springframework.cloud
    spring-cloud-dependencies
    Greenwich.SR6
    pom
    import

    Seata-common代码结构

    com.seata
    seata-parent
    1.0-SNAPSHOT
    ../seata-parent/pom.xml
    4.0.0
    seata-common
    2.6
    3.2.0
    1.18.8
    8.0.17
    1.1.21
    com.baomidou
    mybatis-plus-boot-starter
    ${mybatis-plus.version}
    org.project.lombok
    lombok
    ${lombok.version}
    commons-lang
    commons-lang
    ${commons.lang.version}
    mysql
    mysql-connector-java
    ${mysql.version}
    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-discovery
    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-config
    org.springframework.boot
    spring-boot-starter-jdbc
    com.alibaba
    druid-spring-boot-starter
    ${druid.version}
    org.springframework.boot
    spring-boot-starter-web
    org.springframework.boot
    spring-boot-starter-aop
    org.springframework.boot
    spring-boot-starter-log4j2

    Seata-bank1代码结构

    4.0.0
    com.seata
    seata-bank1
    1.0-SNAPSHOT
    jar
    seata-bank1
    Bank1服务
    org.springframework.boot
    spring-boot-starter-parent
    2.1.12.RELEASE
    UTF-8
    UTF-8
    1.8
    1.8
    1.8
    2.1.0.RELEASE

    Seata-bank2代码结构

    4.0.0
    com.seata
    seata-bank2
    1.0-SNAPSHOT
    jar
    seata-bank2
    Bank2服务
    org.springframework.boot
    spring-boot-starter-parent
    2.1.12.RELEASE
    UTF-8
    UTF-8
    1.8
    1.8
    1.8
    2.1.0.RELEASE

    Seata分布式事务的流程

  • 每个RM(资源管理器)使用DataSourceProxy连接数据库,其目的是使用ConnectionProxy,确保只要有业务操作就一定有Undo Log。
  • 在第一阶段,Undo Log中存放了数据修改前和修改后的值,为事务回滚作好准备。
  • TM(事务管理器)开启全局事务,将XID(全局事务id)放在事务上下文中,通过Feign调用也将XID传入下游分支事务。
  • 每个分支事务将自己的Branch ID(分支事务ID)与XID关联。
  • 在第二阶段,全局事务提交,TC(事务协调器)通知各分支参与者提交分支事务。
  • 在事务提交后,各参与者只需要删除Undo Log即可,并且可以异步执行。
  • 在事务回滚时,TC通知各分支参与者回滚分支事务,通过XID和Branch ID找到相应的回滚日志,生成反向的SQL并执行,以完成分支事务回滚到之前的状态。

  • 测试场景

    1. seata-bank1通过张三用户向李四账户转1元钱,成功场景

    • 张三的账户减少1元
    • 李四的账户增加1元
    • 事务成功完成

    2. seata-bank1通过张三用户向李四账户转1元钱,将seata-bank2关掉,调用李四服务的时候挂掉

    • 张三的账户减少1元
    • 李四的账户没有增加1元
    • 事务回滚,张三的钱恢复到原状
    上一篇:分布式事务解决方案之TCC
    下一篇:分布式事务解决方案之2PC(两阶段提交)入门简介

    发表评论

    最新留言

    留言是一种美德,欢迎回访!
    [***.207.175.100]2025年03月27日 13时55分48秒