文章目录

  • 事务
    • 定义
    • 并发事务
    • 代码实现
  • MVCC
    • 定义
    • 核心机制

事务

定义

什么是事务? 事务是指一组操作要么全部成功,要么全部失败的执行单位。
在数据库中,一个事务通常包含一组SQL语句,系统保证这些语句作为一个整体执行。

为什么引入? 想象一下,若没有事务银行中的转账操作可能会发生:A对B转账,A这边已扣款但B却没收到。这不是亏麻了。再比如,多个线程同时操作一条数据,那么这条数据该听谁的呢?引入事务就是为了解决这些问题,保证数据的完整性,一致性和可靠性。

特性: 有四大特性:

特性全称含义
AAtomicity(原子性)操作不可分割,要么全成功,要么全失败
CConsistency(一致性)执行完事务后,数据要从一个一致状态转到另一个一致状态
IIsolation(隔离性)并发事务之间互不干扰
DDurability(持久性)提交后的数据必须永久保存,即使系统宕机

并发事务

并发事务常见的问题: 了解事务的基本原理后,我们在数据库执行多个事务时,实际上是并发执行。但就像线程并发执行,又会引起很多问题。主要归为以下三类:
(1)脏读:指事务1在访问数据A时,事务2在修改数据A,此时事务1拿到的数据不是最终数据。
如何解决?只需要在事务1中写的过程加锁(可以理解为多线程编程的锁),也就是写的过程不会受到任何外部的干扰。任何事务读到的肯定是写完之后的数据了。

(2)不可重复读:虽然在写的过程加锁可以解决脏读问题,但是没说读的时候不能写啊? 假设事务1读数据A时,事务2在写数据A,事务1读到一半的时候,事务2写完了。此时事务1假设继续读下去,发现内容与前文不一致了。这就是不可重复读。
如何解决?显而易见,给读的过程也加锁。这样读写都不被干预,那么这就不管怎样都安全了吗?

(3)幻读:显然还是不安全,我们考虑一种情况,事务1,2在数据库中读写都加锁了。事务1读取数据A,事务2读取数据A,在事务2读取A时,事务1不能读取A,但它可以操纵数据库的其他的数据。假设事务1新增数据B,事务2在读完数据A后,再查询数据库有多少条数据。发现多了一条,这就是“不敢睁开眼,希望是我的幻觉”(歌词哈哈),大家理解记忆这就是幻读!(当然我理解的可能也有偏差,不过大多数文章都以新增数据举例)。
如何解决?直接彻底串行化,事务2干活的同时,事务1彻底不许做别的了。

问题描述举例
脏读(Dirty Read)一个事务读到另一个事务尚未提交的数据T1更新数据,T2读取了这个数据,后来T1回滚,T2读到的是无效数据
不可重复读(Non-repeatable Read)同一事务中多次读取结果不一致T1两次读取某条记录,中间T2修改了这条记录
幻读(Phantom Read)同一事务中两次查询数据条数不一致T1读取符合条件的所有记录,T2新增了一条符合条件的数据,T1再次读取发现“多出一条”
隔离级别描述会不会出现脏读不可重复读幻读
READ UNCOMMITTED最低,不加锁✅ 有✅ 有✅ 有
READ COMMITTED读已提交(Oracle 默认)❌ 无✅ 有✅ 有
REPEATABLE READ可重复读(MySQL 默认)❌ 无❌ 无✅ 有(InnoDB 用间隙锁避免)
SERIALIZABLE串行化,最高隔离❌ 无❌ 无❌ 无

代码实现

不做重点,感兴趣的可以直接在项目中练习

Connection conn = null;
try {conn = dataSource.getConnection();conn.setAutoCommit(false); // 开启事务// 执行多个 SQL 语句updateAccount1(conn);updateAccount2(conn);conn.commit(); // 提交事务
} catch (Exception e) {if (conn != null) conn.rollback(); // 回滚事务
} finally {if (conn != null) conn.close(); // 关闭连接
}

MVCC

定义

介绍完事务后,我们可以介绍一种更轻量化的解决事务并发问题的方法。讲之前简单讲一下,事务是怎么实现全不做的? 可能会有疑问,事务执行了多个操作,还差几个操作就执行完了,这个时候突发紧急情况不能做了,怎么把之前的操作取消呢。实际上可以理解为数据库已经将之前的版本的数据记录下来,将之前操作所修改的数据全部还原。这就是回滚。

​​什么是MVCC? MVCC -多版本并发控制,它允许事务在不加锁的情况下并发读写,通过维护数据的多个版本实现。神奇吧,竟然不用加锁也可以实现。那么它是怎样版本控制的呢?

为什么引入? 讲原理之前,先要了解之前加锁方案存在的缺陷以及MVCC的目的
加锁方案主要有以下两个问题

传统机制问题
读加共享锁,写加排他锁读写互相阻塞,效率低下
高并发下,锁冲突频繁会造成 锁等待、死锁、性能瓶颈

MVCC目的:
在 无需加锁的前提下,实现“读写分离”、高并发读操作的一致性。也就是避免锁的使用

核心机制

原理
(1)在InnoDB中,MVCC维护每一行的数据多个版本来实现。主要依靠两个字段和undo log机制。

(2)两个字段是指数据库为每条记录隐藏的维护了两个字段分别是更新此记录的事务id和回滚指针。

字段含义
trx_id插入或最后修改该行的事务ID
roll_pointer指向 undo log 中上一个版本的地址,形成版本链

每个事务启动时,系统会分配一个全局递增的事务ID。

(3)undo log
undo log 大家可理解为旧账本,就像夫妻俩一旦吵架就要翻旧账。事务也是如此发生冲突,直接翻旧账。 具体为当一个事务更新记录时,数据库首先将未更新的记录先保存到undo log中,然后事务才可以更新记录,并将记录中的roll_pointer 指向此旧帐本对应的记录。

[当前版本]trx_id: 15roll_pointer --> undo log #1[undo log #1]trx_id: 12roll_pointer --> undo log #2[undo log #2]trx_id: 9

(4)那如何通过翻旧账实现可见性呢?
这里要注意,我们在这通常针对的读操作不加锁,写操作数据库一般默认都会加锁,我们尽可能减少的是读操作的加锁。假设有一组并发的事务开始执行时,系统依次给每个事务分配递增ID。 其中当这里边的事务读取记录时,核心内容就一条即更新这条记录的事务id必须小于这一组事务id的最小值。读取时这条记录才会对事务可见。或者修改这一条记录事务id是它本身,这种情况也是可见的。其他条件,比如大于这一组事务id的最小值,说明更新这条记录的事务id在这一组事务中,由于是并发执行,所以对其不可见。此时,记录的回滚指针会指向之前的版本记录让其事务读取。如下:

判断条件是否可见原因
trx_id == 当前事务ID当前事务自己创建或修改的记录
trx_id < 最小活跃事务ID创建该记录的事务已在当前事务启动前提交
trx_id ∈ 活跃事务列表创建该记录的事务尚未提交
否则否,继续通过 roll_pointer 回滚旧版本找到对当前事务可见的历史版本

这里解释一下可能存在的疑问。 事务出现不会直接获取要读取记录的事务id字段。而是当我们在事务中查询语句执行时,才会获取更新此记录的事务ID。这种方式也叫快照读,就是说读取的时候会给记录拍照定格ReadView。不是事务出现拍照定格。
事务T1如果还没进行读取,是不会生成Read View的。当它真的去执行 SELECT 操作时,它才会拍下“当前全局事务表中的活跃事务ID快照所以 Read View 中的最大事务ID(up_limit_id)可能远远大于当前事务自己的ID

当前活跃的事务创建的 Read View 都是相同的吗?Read View 是每个事务“第一次执行快照读”时才生成的。即便两个事务同时处于“活跃”状态,它们的 Read View 也可能在不同的时刻拍下,因此内容可能不同。快照读和其他操作的区别:

操作类型读写类型是否生成 Read View能否看到未提交数据是否加锁
SELECT快照读(Snapshot Read)✅ 是(第一次读时生成)❌ 否(只能看到历史版本)❌ 否
SELECT ... FOR UPDATE / SELECT ... LOCK IN SHARE MODE当前读(Current Read)❌ 否✅ 是(读取最新已提交或当前数据)✅ 是(加行锁)
UPDATE / DELETE当前读 + 写操作❌ 否✅ 是(读取最新数据)✅ 是(加排他锁)
INSERT写操作❌ 否-(新数据,无历史版本)✅ 是(加插入意向锁)

总结来说,本文面向面试对其基本原理做了一定梳理,希望可以帮助大家通过面试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/88890.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/88890.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/88890.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用 Python 绘制精美雷达图:多维度材料属性对比可视化全指南

&#x1f31f; 为什么选择雷达图&#xff1f;从材料科学到多维数据对比的可视化利器 在科研和数据分析领域&#xff0c;当我们需要同时展示多个维度的数据对比时&#xff0c;传统的柱状图或折线图往往显得力不从心。这时候&#xff0c;雷达图&#xff08;Radar Chart&#xff…

Excel学习03

超级表与图表 Excel中具有超级表的功能。所谓超级表&#xff08;官方名称为“表格”&#xff0c;快捷键CtrlT&#xff09;是Excel中一个强大的数据管理工具&#xff0c;它将普通的数据区域转换为具有只能功能的交互式表格。 这就是表格变为超级表的样子。超级表默认具备冻结窗…

Netflix 网飞的架构演进过程、Java在网飞中的应用|图解

写在前面 上一篇文章中&#xff0c;我们讲解了网飞当前的架构&#xff0c;但网飞的架构并不是一开始就是这样的&#xff0c;而是不断演进发展才是当前的样子。 这篇文章我们就来讲讲网飞架构的演进过程。 第一阶段&#xff1a;Zuul Gateway REST API 使用 Zuul 作为API网关…

使用ros2服务实现人脸检测2-人脸检测功能实现(适合0基础小白)

文章目录 一、用到的库二、使用步骤1.引入库2.获取图片真实路径3.检测人脸4.绘制人脸5.显示结果6.更改setup.py7.完整代码 三、结果展示 一、用到的库 face_recognition&#xff1a;实现在图片中检测人脸。 cv2&#xff1a;显示图片&#xff0c;并且可以在图像中展示检测结果。…

中国农村统计年鉴-Excel版(1985-2024年)

《中国农村统计年鉴》系统收录了全国和各省农村社会经济统计数据&#xff0c;以及近年全国农村主要统计数据&#xff0c;是一部全面反映我国农村社会经济情况的资料性年刊。年鉴内容覆盖农村人口结构、农业产值、主要农产品产量、市场物价、进出口贸易以及收入消费水平等社会经…

golang pprof性能调试工具

简介 pprof是性能调试工具,可以生成类似火焰图、堆栈图,内存分析图等。 整个分析的过程分为两步:1. 导出数据,2. 分析数据。

PPIO × 302.AI:三分钟搭建可共享的聊天机器人

最近&#xff0c;各主流模型厂商频频发布新模型&#xff0c;有一如既往强大的DeepSeek-R1-0528&#xff0c;擅长长输入推理的MiniMax-M1-80k…… 好用的AI大模型这么多&#xff0c;如何才能集成在一个应用自由使用呢&#xff1f;302.AI作为企业级AI应用平台支持各主流模型调用&…

怎么样在自己的网站/独立站中添加视频?

文章目录 **前言** 一、视频在网站/独立站的好处二、视频嵌入网站的原理三、如何简易地把视频嵌入到独立站中&#xff1f; 前言 在信息传播形式日益多元化的当下&#xff0c;静态文字与图片早已无法满足用户对沉浸式浏览体验的需求。视频以其动态画面、声音及文字相结合的特性…

【图像处理基石】什么是摄影的数码味?

“数码味”是一个摄影术语&#xff0c;通常指照片看起来不自然&#xff0c;有过度处理的痕迹&#xff0c;比如色彩过于鲜艳、对比度偏高、高光过曝、阴影死黑&#xff0c;或者有明显的锐化痕迹和噪点。这种现象在手机摄影中尤为常见&#xff0c;因为手机相机的自动算法往往会为…

报表控件stimulsoft教程:在报表、仪表板和 PDF 表单自动生成缩略图

了解缩略图的工作原理在使用Stimulsoft Demo、Stimulsoft Server和Stimulsoft Cloud时非常有用。例如&#xff0c;您可以在此处查看缩略图的实际效果 - 当侧边栏折叠时&#xff0c;将显示缩略图而不是资源列表。在本文中&#xff0c;我们将探讨 Stimulsoft 产品中报表、仪表板和…

变分自编码器(VAE)

1. 从自编码器&#xff08;AE&#xff09;到变分自编码器&#xff08;VAE&#xff09; 自编码器&#xff08;AutoEncoder, AE&#xff09; 基本结构: 自编码器是一种无监督学习模型&#xff0c;通常由两个部分组成&#xff1a; 编码器&#xff08;Encoder&#xff09;&…

ChatboxAI 搭载 GPT 与 DeepSeek,引领科研与知识库管理变革

文章摘要&#xff1a;本文深入探讨 ChatboxAI 在科研领域的应用优势。ChatboxAI 集成多模型&#xff0c;支持全平台&#xff0c;能高效管理科研知识&#xff0c;助力文献检索、实验设计与论文撰写&#xff0c;提升科研效率与质量&#xff0c;同时保障数据安全。其知识库功能可整…

【无刷电机FOC进阶基础准备】【04 clark变换、park变换、等幅值变换】

目录 clark变换park变换等幅值变换 其实我不太记得住什么是clark变换、park变换&#xff0c;我每次要用到这个名词的时候都会上网查一下&#xff0c;因为这就是两个名词而已&#xff0c;但是我能记住的是他们背后的含义。 经过【从零开始实现stm32无刷电机FOC】系列后应该对cla…

Sentinel的流控策略

在 Sentinel 中&#xff0c;流控策略&#xff08;Flow Control Strategy&#xff09;用于定义如何处理请求的流量&#xff0c;并决定在流量达到某个阈值时采取的行动。流控策略是实现系统稳定性和高可用性的核心机制&#xff0c;尤其在高并发环境中&#xff0c;确保服务不会因过…

Ubuntu Extension Manager 插件卸载

Ubuntu 上使用Extension Manager 安装插件&#xff0c;但目前无法在Extension Manager 中卸载。 卸载方式可以通过 gnome-extensions 命令进行卸载&#xff1a; Usage:gnome-extensions COMMAND [ARGS…]Commands:help Print helpversion Print versionenable Enabl…

深度学习中Embedding原理讲解

我们用最直白的方式来理解深度学习中 Embedding&#xff08;嵌入&#xff09; 的概念。 核心思想一句话&#xff1a; Embedding 就是把一些复杂、离散的东西&#xff08;比如文字、类别、ID&#xff09;转换成计算机更容易理解和计算的“数字密码”&#xff0c;这些“数字密码…

(3)Java+Playwright自动化测试-启动浏览器

1.简介 前边两章文章已经将环境搭建好了&#xff0c;今天就在Java项目搭建环境中简单地实践一下&#xff1a; 启动两大浏览器。 接下来我们在Windows系统中启动浏览器即可&#xff0c;其他平台系统的浏览器类似的启动方法&#xff0c;照猫画虎就可以了。 但是在实践过程中&am…

使用OpenWebUI与DeepSeek交互

Open WebUI 是针对 LLM 用户友好的 WebUI,支持的 LLM 运行程序包括阿里百炼、 Ollama、OpenAI 兼容的 API。这里主要讲在Docker环境下安装与本地Ollame和百炼API Key配置 一、安装Docker 1. CentOS # 设置为阿里云的源 sudo yum install -y yum-utils sudo yum-config-mana…

Github 2025-06-25 C开源项目日报 Top9

根据Github Trendings的统计,今日(2025-06-25统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目9C++项目1raylib: 用于视频游戏编程的简单易用图形库 创建周期:3821 天开发语言:C协议类型:zlib LicenseStar数量:18556 个Fork数量:1…

【数据标注师】2D标注

目录 一、 **2D标注知识体系框架**二、 **五阶能力培养体系**▶ **阶段1&#xff1a;基础规则内化&#xff08;1-2周&#xff09;**▶ **阶段2&#xff1a;复杂场景处理技能**▶ **阶段3&#xff1a;专业工具 mastery**▶ **阶段4&#xff1a;领域深度专精▶ **阶段5&#xff1…