当前位置: 首页 > news >正文

分布式事务seata的AT模式介绍

分布式事务seata的AT模式介绍

seata是阿里开源的一款分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,本文主要介绍AT模式的使用。

seata安装

下载seata服务,官方地址:https://github.com/seata/seata/releases
在Linux下,下载完成后,直接解压,通过命令安装即可:

sh ./bin/seata-server.sh

支持的启动参数

参数全写作用备注
-h–host指定在注册中心注册的 IP不指定时获取当前的 IP,外部访问部署在云环境和容器中的 server 建议指定
-p–port指定 server 启动的端口默认为 8091
-m–storeMode事务日志存储方式支持file和db,默认为 file
-n–serverNode用于指定seata-server节点ID,如 1,2,3…, 默认为 1
-e–seataEnv指定 seata-server 运行环境如 dev, test 等, 服务启动时会使用 registry-dev.conf 这样的配置

如:

sh ./bin/seata-server.sh -p 8091 -h 127.0.0.1 -m file

seata的AT模式介绍

AT模式实质是两阶段提交协议的演变,具体如下:

  • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源
  • 二阶段:
    提交异步化,非常快速地完成。

回滚通过一阶段的回滚日志进行反向补偿。

业务背景:
用户调用系统A的store服务,store服务调用系统B的company服务,company服务会新增一条数据,然后把companyId返回系统A,然后系统A通过companyId再新增一条store数据。

一般如果store服务执行失败了,直接抛异常了,所以company服务也不会执行,
但如果store服务执行成功了,已经写了一条数据到数据库,执行company服务时失败了,就会产生数据不一致的问题。

使用seata的AT模式,主要分为下面几个步骤:

  • 配置seata服务及创建事务表
  • 调用方配置(对应上面的store服务)
  • 服务提供方配置(对应上面的company服务)

配置seata服务及创建事务表

配置conf/file.conf文件

store {mode = "db" //修改为db模式,标识事务信息用db存储file {dir = "sessionStore"maxBranchSessionSize = 16384maxGlobalSessionSize = 512fileWriteBufferCacheSize = 16384sessionReloadReadSize = 100flushDiskMode = async}db {datasource = "druid"dbType = "mysql"driverClassName = "com.mysql.cj.jdbc.Driver"url = "jdbc:mysql://192.168.234.1:3306/seata?useUnicode=true&characterEncoding=utf8&useSSL=false&&serverTimezone=UTC" //修改数据库连接user = "seata" //修改数据库账号password = "123456" //修改数据库密码minConn = 5maxConn = 30globalTable = "global_table"branchTable = "branch_table"lockTable = "lock_table"queryLimit = 100}
}service {vgroup_mapping.chuanzh_tx_group = "default" //chuanzh_tx_group为自定义的事务组名称,要和客户端配置保持一致default.grouplist = "192.168.234.128:8091"enableDegrade = falsedisable = falsemax.commit.retry.timeout = "-1"max.rollback.retry.timeout = "-1"
}

上面配置共修改了3个地方:

  1. 存储模式改为db模式,需要创建3张事务表,如下:

    -- the table to store GlobalSession dataCREATE 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 = InnoDBDEFAULT CHARSET = utf8;-- the table to store BranchSession dataCREATE 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 = InnoDBDEFAULT CHARSET = utf8;-- the table to store lock dataCREATE 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 = InnoDBDEFAULT CHARSET = utf8;
    
  2. 修改数据库连接,注意如果你安装的是MySQL8,则需要修改MySQL8的驱动:driverClassName = “com.mysql.cj.jdbc.Driver”,不然会出现启动报错的问题,详细请参考:seata启动MySQL报错 #359。

  3. 修改事务的组名,你也可以不修改,我这里使用的是:chuanzh_tx_group

  4. 创建业务事务表,记录业务需要回滚的数据,在分布式事务中,每个参与的业务数据库都需要添加对应的表

    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=1 DEFAULT CHARSET=utf8;
    

配置conf/registry.conf文件

registry {type = "eureka"  修改注册方式,微服务调用使用的是Eurekanacos {serverAddr = "localhost"namespace = ""cluster = "default"}eureka {serviceUrl = "http://192.168.234.1:8081/eureka"  //修改Eureka地址application = "default"  weight = "1"}redis {serverAddr = "localhost:6379"db = "0"}zk {cluster = "default"serverAddr = "127.0.0.1:2181"session.timeout = 6000connect.timeout = 2000}consul {cluster = "default"serverAddr = "127.0.0.1:8500"}etcd3 {cluster = "default"serverAddr = "http://localhost:2379"}sofa {serverAddr = "127.0.0.1:9603"application = "default"region = "DEFAULT_ZONE"datacenter = "DefaultDataCenter"cluster = "default"group = "SEATA_GROUP"addressWaitTime = "3000"}file {name = "file.conf"}
}

以上修改了使用Eureka方式注册,并配置了Eureka地址,启动MySQL、Eureka服务后,就可以启动seata服务了。

调用方配置(store-server)

maven配置,使用seata-spring-boot-starter,自动配置的方式,不需要再添加file.conf和register.conf文件

    <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid-spring-boot-starter.version}</version></dependency><dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>1.2.0</version></dependency>

application.properties配置:

server.port=9090
spring.application.name=store-servermybatis.type-aliases-package=com.chuanzh.model
mybatis.mapper-locations=classpath:mapper/*.xmlspring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driverseata.tx-service-group=chuanzh_tx_group
seata.service.vgroup-mapping.chuanzh_tx_group=default
seata.service.grouplist.default=192.168.234.128:8091logging.level.io.seata=DEBUGeureka.client.serviceUrl.defaultZone= http://localhost:8081/eureka/

数据源配置,因为seata是对数据库的datasource进行了接管和代理,所以在每个参与分布式事务的数据源都要进行如下配置:

@Configuration
public class DataSourceConfiguration {@Bean@ConfigurationProperties(prefix = "spring.datasource")public DataSource druidDataSource(){DruidDataSource druidDataSource = new DruidDataSource();return druidDataSource;}@Primary@Bean("dataSource")public DataSourceProxy dataSource(DataSource druidDataSource){return new DataSourceProxy(druidDataSource);}@Beanpublic SqlSessionFactory sqlSessionFactory(DataSourceProxy dataSourceProxy)throws Exception{SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSourceProxy);sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/*.xml"));sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());return sqlSessionFactoryBean.getObject();}}

注意配置了数据源后,还需要在启动类排除dataSource自动配置,不然会出现循环依赖的问题,如下,其它的解决方法,可以参考:集成fescar数据源循环依赖错误解决方案

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

配置请求拦截器,生成一个请求事务ID,用于在微服务中传递

@Configuration
public class SeataRequestInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate requestTemplate) {String xid = RootContext.getXID();if (StringUtils.isNotBlank(xid)) {requestTemplate.header("TX_XID", xid);}}
}

服务提供方配置(company-server)

maven、application.properties、数据源配置同调用方配置,区别主要是拦截器的配置,如下:

@Slf4j
@Component
public class SeataHandlerInterceptor implements HandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String xid = RootContext.getXID();String rpcXid = request.getHeader("TX_XID");if(log.isDebugEnabled()) {log.debug("xid in RootContext {} xid in RpcContext {}", xid, rpcXid);}if(xid == null && rpcXid != null) {RootContext.bind(rpcXid);if(log.isDebugEnabled()) {log.debug("bind {} to RootContext", rpcXid);}}return true;}public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {String rpcXid = request.getHeader("TX_XID");if(!StringUtils.isEmpty(rpcXid)) {String unbindXid = RootContext.unbind();if(log.isDebugEnabled()) {log.debug("unbind {} from RootContext", unbindXid);}if(!rpcXid.equalsIgnoreCase(unbindXid)) {log.warn("xid in change during RPC from {} to {}", rpcXid, unbindXid);if(unbindXid != null) {RootContext.bind(unbindXid);log.warn("bind {} back to RootContext", unbindXid);}}}}}
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {@Autowiredprivate SeataHandlerInterceptor seataHandlerInterceptor;public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(seataHandlerInterceptor).addPathPatterns(new String[]{"/**"});}}

添加全局事务注解

在服务调用方的方法上添加@GlobalTransactional注解,下面模拟了一种场景,如果companyId为偶数,则会抛异常。

    @GlobalTransactional(rollbackFor = Exception.class)public void create(StoreEntity storeEntity) throws Exception {CompanyEntity companyEntity = new CompanyEntity();companyEntity.setName(storeEntity.getName());companyEntity = companyFeign.createCompany(companyEntity);if (companyEntity.getId() % 2 == 0) {throw new Exception();}storeEntity.setCompanyId(companyEntity.getId());storeMapper.insert(storeEntity);}

经过测试,companyFeign.createCompany服务调用后会先向数据库写一条数据,当create方法执行抛异常,就会事务回滚,删除掉原先的company数据

相关文章:

分布式事务seata的AT模式介绍

分布式事务seata的AT模式介绍 seata是阿里开源的一款分布式事务解决方案&#xff0c;致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式&#xff0c;本文主要介绍AT模式的使用。 seata安装 下载seata服务&#xff0c;官方地址…...

初识Linux(1),看了这篇文章,妈妈再也不用担心我Linux找不到门了。

文章目录 前言1. ls 指令例如&#xff1a;只显示文件名属性ls显示文件详细属性 ls - l 该操作可以简写成ll查看隐藏文件ls -l -a 2.pwd例如&#xff1a;显示当前目录所处的路径类似于windows如下操作: 3.cd 指令例如&#xff1a;改变工作目录相当于windows如下操作 4.whoami 指…...

甲烷产生及氧化

温室气体排放被认为是加速气候变化的重要因素&#xff0c;甲烷(CH4)是仅次于二氧化碳(CO2)的重要温室气体&#xff0c;其百年温室效应潜势是CO2的28倍[1-2]。湿地中的CH4由产甲烷古菌在水体底部或沉积层严格厌氧环境下产生并释放进入水体&#xff0c;产生的CH4向上覆水运输过程…...

Javascript的form表单校验输入框

以下是HTML代码&#xff1a; <form name"myForm" onsubmit"return validateForm()"><label for"name">姓名&#xff1a;</label><input type"text" id"name" name"name"><br><l…...

大数据-之LibrA数据库系统告警处理(ALM-37003 GTM主备不同步或者GTM主备断连)

告警解释 当GTM主实例与GTM备实例连接异常或者GTM主实例未处于同步状态时&#xff0c;产生该告警。 告警属性 告警ID 告警级别 可自动清除 37003 严重 是 告警参数 参数名称 参数含义 ServiceName 产生告警的服务名称 RoleName 产生告警的角色名称 HostName 产…...

python每日一题——4移动0

题目 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0]…...

CAN实验

CAN 寄存器 HAL库函数 代码 #include "./BSP/CAN/can.h"CAN_HandleTypeDef g_can1_handle; CAN_TxHeaderTypeDef g_can1_txheader; CAN_RxHeaderTypeDef g_can1_rxheader;/* STM32F103 TS1 8 TS2 7 BRP 3 波特率&#xff1a;36000 / [(9 8 1) * 4] 500Kbps …...

(一)pytest自动化测试框架之生成测试报告(mac系统)

前言 我们可以通过pytest-html插件来生成测试报告&#xff0c;但是pytest-html插件生成的测试报告不够美观&#xff0c;逼格也不够高&#xff0c;通过allure生成的测试报告是比较美观的&#xff0c;花里胡哨的&#xff0c;能够提升一个level。 allure官网&#xff1a; Allure…...

微服务实战系列之Nginx

前言 Nginx&#xff1f;写了那么多文章&#xff0c;为什么今天才轮到它的表演&#xff1f;那是因为它实在太重要了&#xff0c;值得大书特书&#xff0c;特别对待。 当我们遇到单点瓶颈&#xff0c;第一个idea是&#xff1f;Nginx&#xff1b; 当我们需要反向代理&#xff0c;…...

使用rsync从OpenShift的pod复制文件

环境 Red Hat Enterprise Linux release 8.6 (Ootpa)OCP 4.12.22 准备 安装rsync&#xff1a; yum install rsync 查看pod&#xff1a; [rootapi.kai1123.cp.fyre.ibm.com ~]# oc get pod -n cpd-instance | grep dmc ...... ibm-dmc-1700727413211000-monitor-0 …...

解决Activiti5.22流程图部署在Windows上正常,但在linux上部署后出现中文变方块的问题

总结/朱季谦 楼主最近在做公司的工作流平台&#xff0c;发现一个很无语的事情&#xff0c;Activiti5.22的流程图在Windows环境上部署&#xff0c;是可以正常查看的&#xff0c;但发布到公司的Linux服务器上后&#xff0c;在上面进行流程图在线部署时&#xff0c;发现中文都变成…...

EMG肌肉电信号处理合集(三)

本文主要展示常见的肌电信号预处理的实现&#xff0c;开发环境为matlab。 目录 1 肌电信号低通&#xff0c;高通&#xff0c;带通滤波 2 去除DC 0阶偏置&#xff0c;1阶偏置 3 全波整流 4 信号降采样 5 linear envolope / butterworth 低通滤波器 1 肌电信号低通&#xf…...

GitHub桌面版

GitHub桌面版 一、GitHub 桌面版二、clone 仓库三、更新仓库 一、GitHub 桌面版 二、clone 仓库 三、更新仓库...

【广州华锐互动】昆虫3D虚拟动态展示:探索神奇的微观世界

在这个充满科技魅力的时代&#xff0c;我们可以通过各种方式去了解和探索自然界的奥秘。而昆虫作为地球上最为丰富多样的生物群体之一&#xff0c;其独特的生活习性和形态特征一直吸引着人们的目光。 由广州华锐互动开发的昆虫3D虚拟动态展示系统&#xff0c;成为了一种全新的科…...

《QT从基础到进阶·三十六》QWidget实现收缩栏的效果

功能&#xff1a; 1、可以在收缩栏插件中添加界面 2、可以把界面展开或收缩 3、可以用鼠标拖动界面改变界面的排放顺序 源码放在最下方 1、可以在收缩栏插件中添加界面 virtual void addWidget(QWidget* widget, const QString& label, const QIcon& icon QIcon())…...

运行软件报错找不到vcruntime140.dll无法继续执行代码怎么办-6个解决方法

vcruntime140.dll是一个由Microsoft Visual C提供的运行时库文件&#xff0c;它为许多Microsoft Visual Studio开发的应用程序提供了必要的支持。这个文件对于许多Windows应用程序的正常运行至关重要。然而&#xff0c;有时会出现vcruntime140.dll缺失的问题&#xff0c;导致应…...

从Discord的做法中学习 — 使用Golang进行请求合并

正如你可能之前看到的&#xff0c;Discord去年发布了一篇有价值的文章&#xff0c;讨论了他们成功存储了数万亿条消息。虽然有很多关于这篇文章的YouTube视频和文章&#xff0c;但我认为这篇文章中一个名为“数据服务为数据服务”的部分没有得到足够的关注。在这篇文章中&#…...

【教3妹学编程-算法题】统计和小于目标的下标对数目

2哥 : 3妹&#xff0c;OpenAI的宫斗剧迎来了大结局&#xff01;OpenAI宣布阿尔特曼复职CEO&#xff0c;董事会重组 3妹&#xff1a;啊&#xff1f;到底谁才是幕后操纵者啊&#xff0c;有咩有揪出来 2哥 : 也不是很清楚&#xff0c;据说在被开除的几周前&#xff0c;前CEO曾谴责…...

OSG粒子系统与阴影-雾效模拟(1)

虚拟现实中有很多效果&#xff0c;如雨效、雪效、雾效等&#xff0c;这些都可以通过粒子系统来实现。一个真实的粒子系统的模式能使三维场景达到更好的效果。 本章对OSG粒子系统的使用以及生成自定义粒子系统的方法进行了详细介绍最后还附带说明了阴影的使用方法。在实时的场景…...

Windows power shell for循环

有时候需要重复执行某个shell命令 for($i1;$i -lt 10;$i$i1){echo $i}如果是cmd for /l %i in (1,1,5) do echo %i...

WinUtil:Windows系统优化与管理的全栈解决方案,提升系统效率50%以上

WinUtil&#xff1a;Windows系统优化与管理的全栈解决方案&#xff0c;提升系统效率50%以上 【免费下载链接】winutil Chris Titus Techs Windows Utility - Install Programs, Tweaks, Fixes, and Updates 项目地址: https://gitcode.com/GitHub_Trending/wi/winutil W…...

Halcon仿射变换的“魔法”与“陷阱”:从vector_angle_to_rigid到hom_mat2d_rotate的旋转中心到底在哪?

Halcon仿射变换的“魔法”与“陷阱”&#xff1a;从vector_angle_to_rigid到hom_mat2d_rotate的旋转中心到底在哪&#xff1f; 在工业视觉开发中&#xff0c;仿射变换就像一把瑞士军刀&#xff0c;能解决图像对齐、坐标转换、物体定位等核心问题。但当你自信满满地写下hom_mat2…...

告别官方Example!手把手教你为Xilinx Aurora 8B/10B IP核定制自己的数据流(Vivado 2017.4)

从零构建Xilinx Aurora 8B/10B自定义数据流&#xff1a;实战指南 在FPGA高速串行通信领域&#xff0c;Xilinx的Aurora 8B/10B协议因其简洁高效而广受欢迎。然而&#xff0c;许多工程师在实际项目中都会遇到一个共同困境&#xff1a;官方提供的Example Design虽然功能完整&#…...

ROS2 仿真入门01 Gazebo 核心界面功能全解析

1. Gazebo初体验&#xff1a;从零启动到界面认知 第一次打开Gazebo的感觉&#xff0c;就像走进了一个充满机关的机器人实验室。作为ROS2仿真生态的核心工具&#xff0c;这个开源的3D物理仿真环境能让你在虚拟世界中构建从简单机械臂到自动驾驶系统的任何场景。还记得我刚开始接…...

VideoSrt:5分钟搞定专业视频字幕的智能工具

VideoSrt&#xff1a;5分钟搞定专业视频字幕的智能工具 【免费下载链接】video-srt-windows 这是一个可以识别视频语音自动生成字幕SRT文件的开源 Windows-GUI 软件工具。 项目地址: https://gitcode.com/gh_mirrors/vi/video-srt-windows 还在为视频字幕制作耗费大量时…...

Verdi调试实战:从波形异常到快速定位Force信号的三种方法(附配置命令)

Verdi调试实战&#xff1a;从波形异常到快速定位Force信号的三种方法&#xff08;附配置命令&#xff09; 在数字IC验证的日常工作中&#xff0c;波形调试占据了工程师大量时间。当发现某个信号行为与预期不符时&#xff0c;如何快速判断是否为force操作导致&#xff0c;并准确…...

别再手动截图了!用Docker跑个Headless Chrome,Java代码5分钟搞定网页PDF生成

5分钟实现网页PDF自动化&#xff1a;基于DockerJava的无头浏览器实战方案 每次手动截图保存网页内容时&#xff0c;是否觉得这种重复操作既低效又容易出错&#xff1f;想象一下&#xff1a;凌晨三点系统自动将运营报告生成PDF归档&#xff0c;或是批量导出数百个产品页面的标准…...

别再死记硬背音标了!用《瑞秋英语》和《美语发音秘诀》的方法,搞定美式发音的连读弱读

告别机械记忆&#xff1a;用自然语流训练法重塑你的美式发音 当大多数人翻开英语发音教材时&#xff0c;映入眼帘的往往是密密麻麻的音标符号和机械的单词发音示范。这种割裂式的学习方法让我们误以为掌握发音就是记住每个音标的正确口型&#xff0c;却忽略了真实对话中音与音之…...

超越简单余弦距离:用‘局部残差’思想为你的图像特征匹配加个Buff

超越简单余弦距离&#xff1a;用‘局部残差’思想为你的图像特征匹配加个Buff 当你在电商平台搜索"白色连衣裙"时&#xff0c;系统如何在数百万商品图中精准找到最符合预期的款式&#xff1f;当你在手机相册输入"海滩日落"时&#xff0c;算法又是怎样从数万…...

QQ音乐全能解析工具:智能解锁音乐世界的终极利器

QQ音乐全能解析工具&#xff1a;智能解锁音乐世界的终极利器 【免费下载链接】MCQTSS_QQMusic QQ音乐解析 项目地址: https://gitcode.com/gh_mirrors/mc/MCQTSS_QQMusic 在数字音乐时代&#xff0c;音乐爱好者们常常面临这样的困境&#xff1a;心仪的歌曲被平台限制&am…...