原理底层计划--分布式事务
分布式事务
mysql事务
我们通过show engines查询存储引擎,mysql一般为innodb,
为什么?
因为innodb支持事务是原因之一。
特性无非ACID
原子性,一致性,隔离性,持久性
一致性是最后追求的结果,也就保证了数据的安全性。
innodb自动有事务,我们不需要再搭建事务。
只是我们要关注事务并发出现的问题
🌴 脏读:对于两个事务T1,T2,T1读取了已经被T2更新但还没有被提交的字段之后,若T2回滚,T1读取的内容就是临时且无效的
🌴不可重复读 :对于两个事务T1,T2,T1读取了一个字段,然后T2更新了该字段之后,T1在读取同一个字段,值就不同了
🌴 幻读:对于两个事务T1,T2,T1在A表中读取了一个字段,然后T2又在A表中插入了一些新的数据时,T1再读取该表时,就会发现神不知鬼不觉的多出几行了…
隔离级别:可提交读 不可提交读 可串行化
- read uncommitted(读未提交数据):允许事务读取未被其他事务提交的变更。(脏读、不可重复读和幻读的问题都会出现)。
- read committed(读已提交数据):只允许事务读取已经被其他事务提交的变更。(可以避免脏读,但不可重复读和幻读的问题仍然可能出现)
3.repeatable read(可重复读):确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新(update)。(可以避免脏读和不可重复读,但幻读仍然存在) - serializable(串行化):确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作,所有并发问题都可避免,但性能十分低下(因为你不完成就都不可以弄,效率太低)
select @@tx_isolation 语句查询当前的隔离级别,使用最多:读已提交、可重复读
Spring事务一个注解解决
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
Propagation.REQUIRED
支持当前事务,如果当前没有事务,就新建一个事务。(默认)
Propagation.SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行。
Propagation.MANDATORY
支持当前事务,如果当前没有事务,就抛出异常。
Propagation.REQUIRES_NEW
新建事务,如果当前存在事务,把当前事务挂起。
Propagation.NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
Propagation.NEVER
以非事务方式执行,如果当前存在事务,则抛出异常。
Propagation.NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
分布式事务
Spring Boot 微服务里面有个注解是 @EnableTransactionManagement ,其实这个就是本地事务。这个不是分布式事务。
redis可以支持分布式事务实现,但是不推荐使用;
redis也可以做消息中间件,但不推荐使用。
redis更擅长的事缓存,非关系型数据库层面。
rocketMq支持分布式事务,Kafka不支持事务
RocketMQ事务流程关键
事务消息在一阶段对用户不可见
事务消息相对普通消息最大的特点就是一阶段发送的消息对用户是不可见的,也就是说消费者不能直接消费。这里RocketMQ的实现方法是原消息的主题与消息消费队列,然后把主题改成 RMQ_SYS_TRANS_HALF_TOPIC ,这样由于消费者没有订阅这个主题,所以不会被消费。
如何处理第二阶段的失败消息?
在本地事务执行完成后会向MQServer发送Commit或Rollback操作,此时如果在发送消息的时候生产者出故障了,那么要保证这条消息最终被消费,MQServer会像服务端发送回查请求,确认本地事务的执行状态。
当然了rocketmq并不会无休止的的信息事务状态回查,默认回查15次,如果15次回查还是无法得知事务状态,RocketMQ默认回滚该消息。
消息状态 事务消息有三种状态:TransactionStatus.CommitTransaction:提交事务消息,消费者可以消费此消息
TransactionStatus.RollbackTransaction:回滚事务,它代表该消息将被删除,不允许被消费。
TransactionStatus.Unknown :中间状态,它代表需要检查消息队列来确定状态。
所以分布式事务解决方案参考思路如下,采用rocketmq实现,方案和假代码如下:
本地消息表(所有mq都可以)
本地消息表其实就是利用了 各系统本地的事务来实现分布式事务。
当系统 A 被其他系统B调用发生数据库表更操作,首先会更新数据库的业务表,其次会往相同数据库的消息表和记录表中插入一条数据,两个操作发生在同一个事务中
如果消息表没有插入进去,说明第一步更新业务表失败了,那么下一步就不用进行了
@Test
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void transactionStart(User user, MessageTable messageTable) {//假设user是要修改的数据userService.updateById(user);messageTableSevice.insert(messageTable);logService.insert(messageTable);//下面不一定要轮询,可以在这里同时发送mq消息}
系统 A 的脚本定期轮询或者定时器本地消息往 mq 中写入一条消息,如果消息发送失败会进行重试
@Test
//每分钟
@Scheduled(cron = "0/60 * * * * ?}")
public void loopSend() {List<MessageTable> messageTables = messageTableSevice.selectAllByNoDel();if (CollectionUtil.isEmpty(messageTables)) {return;}messageTables.forEach(item -> {//value存放请求参数(对象转字符串),然后在b消费的时候,用到//body字节数组就行byte[] body = new byte[0];try {body = this.getByteArrayByObject(item.getValue());} catch (IOException e) {throw new RuntimeException(e);}String key = "TRANSACTION_KEY";//可靠性高采用同步SendResult sendResult = this.sendMsg(mqTopicConfig.getSaasReportTopic(), mqTopicConfig.getSaasTopicTagRunReport(), body, key);log.info("log: " + sendResult.toString());});}
/*** 对象转字符数组 假代码* @param messageTable* @return* @throws IOException*/
public byte[] getByteArrayByObject(Object messageTable) throws IOException {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(messageTable);byte[] bytes = byteArrayOutputStream.toByteArray();byteArrayOutputStream.close();objectOutputStream.close();return bytes;
}
public Object getObjectByByteArray(byte[] bytes) throws IOException, ClassNotFoundException {final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);final ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);final Object object = objectInputStream.readObject();byteArrayInputStream.close();objectInputStream.close();return object;
}
工具类发送消息改造一下,byte[] body不去转成String,直接传字节流就行了;如果要转String,这样:
messageBody.getBytes(StandardCharsets.UTF_8)public SendResult sendMsg(String topic, String msgTag, byte[] messageBody, String msgKey) {//byte[] bytes = messageBody.getBytes(StandardCharsets.UTF_8);org.apache.rocketmq.common.message.Message msg = new org.apache.rocketmq.common.message.Message(topic, msgTag, msgKey, messageBody);return this.send(msg, Boolean.FALSE);}
private SendResult send(org.apache.rocketmq.common.message.Message msg, Boolean isOneWay) {try {if (isOneWay) {this.producer.sendOneway(msg);log.info("....");return null;} else {SendResult sendResult = this.producer.send(msg);if (sendResult != null) {log.info("....");return sendResult;} else {log.error("...");return null;}}} catch (Exception var4) {log.error("...");return null;}}
系统 B 消费 mq 中的消息,并处理业务逻辑。如果本地事务处理失败,会在继续消费 mq 中的消息进行重试,如果业务上的失败,可以通知系统 A 进行回滚操作,也就是根据记录的数据进行补偿;
public Action consume(Message message, ConsumeContext consumeContext) {try {log.info("start get consume");byte[] body1 = message.getBody();Object objectByByteArray = this.getObjectByByteArray(body1);MessageTable messageTable = (MessageTable) objectByByteArray;//String body = new String(message.getBody(), StandardCharsets.UTF_8);if (null == messageTable) {//如果body不存在,CommitMessagelog.info("body is null");return Action.CommitMessage;}log.info("messageTable:{}", messageTable);//本地业务 body字符串转回来对象Integer a = bService.update(messageTable);//失败的话要回滚if (a <= 0) {//根据日志信息回滚回去 就是补偿机制userService.updateById(user);}return Action.CommitMessage;} catch (Exception e) {log.error("consume fail", e);return Action.CommitMessage;}
}
相关文章:
原理底层计划--分布式事务
分布式事务 mysql事务 我们通过show engines查询存储引擎,mysql一般为innodb, 为什么? 因为innodb支持事务是原因之一。 特性无非ACID 原子性,一致性,隔离性,持久性 一致性是最后追求的结果,也就保证了数…...
Hive总结
文章目录一、Hive基本概念二、Hive数据类型三、DDL,DML,DQL1 DDL操作2 DML操作3 DQL操作四、分区操作和分桶操作1、分区操作2、分桶操作五、Hive函数六、文件格式和压缩格式一、Hive基本概念 Hive是什么? Hive:由 Facebook 开源用于解决海量结构化日志的…...
docker环境下安装jenkins
前言 差点被Jenkins的插件搞麻了,又是依赖不对又是版本需要升级的,差点破口大骂了,还好忍住了,静下心来慢慢搞,终于搞通了。这里必须记录一下。 废话不多说,上来就是干,jenkins是干嘛用的&…...
Shifu基础功能:设备接入
如何修改设备接入的配置 1. 编辑edgedevice.yaml文件 接入设备前,您需要对edgedevice.yaml文件进行编辑。对于不同的协议,protocolSettings可根据协议进行进一步配置,详细配置请前往Shifu API参考。 ... connection: Ethernet address: …...
基于Java+SpringBoot+Vue+Redis+RabbitMq的鲜花商城
基于JavaSpringBootVueRedisRabbitMq的鲜花商城 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、…...
蓝桥杯真题(解码)小白入!
本来看这个题感觉很简单,不就是Ascall值换来换去嘛,其实也真的这样,但是对于小白来说,ascall根本记不住 题目说了,每个数不会重复超过9次(这见到那多了,不然根本不会写) 其次如何实现…...
并发包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别?
第20讲 | 并发包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别? 在上一讲中,我分析了 Java 并发包中的部分内容,今天我来介绍一下线程安全队列。Java 标准库提供了非常多的线程安全队列,很容易混淆。 今天我要问你的…...
分享四个前端Web3D动画库在Threejs中使用的动画库以及优缺点附地址
Threejs中可以使用以下几种动画库:Tween.js:Tween.js是一个简单的缓动库,可以用于在three.js中创建简单的动画效果。它可以控制数值、颜色、矢量等数据类型,并提供了多种缓动函数,例如线性、弹簧、强化、缓冲等等。区别…...
谷歌浏览器和火狐浏览器永久禁用缓存【一劳永逸的解决方式】
目录 前言 谷歌浏览器 方式一 方式二 火狐浏览器 前言 缓存对于开发人员来说异常的痛苦,很多莫名其妙的bug就是由缓存导致的,但当我们在网上查找禁用缓存的方式时,找到的方式大多数都是在开发者工具的面板中勾选禁用缓存的选项,但这种方式有个弊端就是需要一直打开这个…...
kibana查看日志
一、背景 kibana收集日志功能很强大,之前只是简单的使用,此次系统学习了解并分享一波 二、kibana查看日志的基本使用 1.选择查询的服务和日志文件 注意:每个应用配置了开发与生产环境,需要找到指定的应用 1.1选择对应的应用 1.…...
JS 异步接口调用介绍
JS 异步接口调用介绍 Js 单线程模型 JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。这样设计的方案主要源于其语言特性,因为 JavaScript 是浏览器脚本语言,它可以操纵 DOM ,可以渲染动画&a…...
5.深入理解HttpSecurity的设计
深入理解HttpSecurity的设计 一、HttpSecurity的应用 在前章节的介绍中我们讲解了基于配置文件的使用方式,也就是如下的使用。 也就是在配置文件中通过 security:http 等标签来定义了认证需要的相关信息,但是在SpringBoot项目中,我们慢慢脱离…...
opencv-python numpy常见的api接口汇总(持续更新)
前言 最近写代码总是提笔忘api,因为图像处理代码写的比较多,所以想着把一些常用的opencv的api,包括numpy的api做一个记录,后面再忘记的时候,就不用去google挨个搜索了,只需要在自己的博客中一查就全知道了…...
概率论小课堂:伯努利实验(正确理解随机性,理解现实概率和理想概率的偏差)
文章目录 引言I 伯努利试验1.1 伯努利分布(二项式分布)1.2 数学期望值(简称期望值)1.3 平方差(简称方差)1.4 标准差1.5 小结引言 假设买彩票中奖的概率是一百万分之一,如果要想确保成功一次,要买260万次彩票。你即使中一回大奖,花的钱要远比获得的多得多。 很多人喜…...
加密功能实现
文章目录1. 前言2. 密码加密1. 前言 本文 主要实现 对密码进行加密 ,因为 使用 md5 容易被穷举 (彩虹表) 而破解 ,使用 spring security 框架又太大了 (杀鸡用牛刀) 。 所以本文 就自己实现一个密码加密 . 2. 密码加密 这里我们通过 加盐是方式 来 对…...
大数据项目实战之数据仓库:用户行为采集平台——第1章 数据仓库概念
第1章 数据仓库概念 数据仓库(Data Warehouse),是为企业制定决策,提供数据支持的。可以帮助企业改进业务流程、提高产品质量等。 数据仓库的输入数据通常包括:业务数据、用户行为数据和爬虫数据等 业务数据…...
NTP对时服务器(NTP电子时钟)在生物制药业应用
NTP对时服务器(NTP电子时钟)在生物制药业应用 NTP对时服务器(NTP电子时钟)在生物制药业应用 8.1 系统概述 时钟系统为生物制药厂网络控制中心调度员、车场值班员及各部门工作人员提供统一的标准时间信息,也为本工程其它…...
JPA 之 QueryDSL-JPA 使用指南
Querydsl-JPA 框架(推荐) 官网:传送门 参考: JPA整合Querydsl入门篇SpringBoot环境下QueryDSL-JPA的入门及进阶 概述及依赖、插件、生成查询实体 1.Querydsl支持代码自动完成,因为是纯Java API编写查询࿰…...
如何找回回收站删除的视频?这三种方法可以试试
在使用电脑过程中,我们可能会误删重要的文件,特别是影音文件。在这样的情况下,我们可以从计算机的回收站中找回已经被删除的视频。但是有时候,我们可能会不小心清空回收站,这时候就需要一些技巧来恢复回收站删除的视频…...
FPGA_边沿监测理解
一、简易频率计设计中为什么一定要获取下降沿?gate_a:实际闸门信号gate_a_stand:将实际闸门信号打一拍之后的信号gate_a_fall_s:下降沿标志信号cnt_clk_stand: Y值,即在实际闸门信号下,标准时钟信号的周期个数cnt_clk_stand_reg:保存Y值的寄存器核心问题…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
