快照读和当前读

        在 MySQL 中,数据读取方式主要分为 快照读 和 当前读,二者的核心区别在于是否依赖 MVCC(多版本并发控制)的历史版本、是否加锁,以及读取的数据版本是否为最新。以下是详细说明:

一、快照读(Snapshot Read)

定义

        快照读是指读取 MVCC 机制保存的历史数据版本,通过事务启动时生成的一致性视图(Read View)获取数据,不加锁,因此不会阻塞其他事务的读写操作。

触发场景

所有 不加锁的普通 SELECT 语句 均为快照读,例如:

  • SELECT * FROM 表 WHERE id = 1;
  • SELECT name FROM 表 WHERE status = 'active';
核心特点
  • 依赖隔离级别
    • 在 读已提交(Read Committed) 级别:每次 SELECT 都会生成新的 Read View,只能看到已提交的最新数据(避免脏读)。
    • 在 可重复读(Repeatable Read) 级别:整个事务内使用同一个 Read View,多次读取结果一致(避免不可重复读)。
  • 无锁阻塞:读取时不申请任何锁,不影响其他事务的修改。
  • 不读取未提交数据:只能看到符合隔离级别的历史提交版本,看不到其他事务未提交的修改。

二、当前读(Current Read)

定义

        当前读是指读取数据的 最新版本(无视 MVCC 历史版本),且读取时会对目标行 加锁(共享锁或排他锁),以保证数据修改的原子性和一致性。

触发场景

所有 需要获取最新数据并加锁的操作 均为当前读,包括:

  1. 写操作INSERTUPDATEDELETE

    • 执行这些操作时,会先读取最新数据版本,然后对目标行加 排他锁(X 锁),防止其他事务同时修改。
    • 例如:UPDATE 表 SET name = 'b' WHERE id = 1; 会先当前读 id=1 的最新行,加 X 锁后修改。
  2. 加锁的 SELECT 语句

    • SELECT ... FOR SHARE(或 SELECT ... LOCK IN SHARE MODE):加 共享锁(S 锁),允许其他事务读,但阻止其他事务加排他锁。
    • SELECT ... FOR UPDATE:加 排他锁(X 锁),阻止其他事务加共享锁或排他锁。
核心特点
  • 读取最新版本:直接读取当前内存中已提交或未提交的最新数据(即使其他事务未提交,也能看到其修改)。
  • 加锁阻塞:会对目标行加锁,其他事务若需操作同一行,需等待锁释放(提交或回滚)。
  • 保证数据一致性:常用于需要精确修改最新数据的场景(如并发更新),避免丢失更新。

三、其他特殊读取情况?

除了快照读和当前读,MySQL 中没有其他独立的读取方式,但需注意以下特殊场景:

  1. 串行化(Serializable)隔离级别下的读

    • 在最高隔离级别 “串行化” 中,普通 SELECT 会被隐式转换为 当前读(加共享锁),以完全避免并发问题。此时快照读机制不生效,本质仍是当前读的一种特殊表现。

                也就是说在串行化隔离级别下,线程 B 会等待线程 A 提交或回滚后,读取到线程 A 提交后的数据或回滚前的原始数据。A没提交或没回滚时,线程B的读取被阻塞

  1. DDL 操作中的读

    • 执行 ALTER TABLE 等 DDL 语句时,会对表加 metadata 锁(MDL 锁),此时的读操作可能被阻塞,但读取方式仍属于快照读或当前读(取决于具体语句是否加锁)。

总结:核心区别与场景表

读取方式触发场景是否加锁读取的数据版本典型操作示例
快照读不加锁的普通 SELECT不加锁MVCC 历史提交版本SELECT * FROM 表;
当前读写操作(INSERT/UPDATE/DELETE)、加锁 SELECT加锁(S 或 X 锁)最新版本(含未提交)UPDATE 表 SET ...;SELECT ... FOR UPDATE;

MySQL 可重复读隔离级别下的事务锁与数据可见性

1. 核心场景

  • 初始数据:表中某行 name = 'a'
  • 线程 A:开启事务,执行 UPDATE 表 SET name = 'b' WHERE name = 'a'(未提交)。
  • 线程 B:开启事务,执行 UPDATE 表 SET name = 'c' WHERE name = 'b'
    • 如果线程B是UPDATE 表 SET name = 'c' WHERE name = 'a',因为是当前读,所以name已经被线程A修改,所以找不到WHERE name = 'a',也就无事发生

2. 关键机制

  1. 当前读(Current Read)

    • UPDATE/DELETE/INSERT/SELECT ... FOR UPDATE 会触发当前读,直接读取最新数据(无论是否提交)。
    • 与快照读的区别:普通 SELECT 使用事务启动时的一致性视图(MVCC),当前读无视视图,读取最新版本。
  2. 排他锁(X 锁)

    • UPDATE 会对匹配的行加排他锁,阻止其他事务同时修改。
    • 锁持有至事务提交 / 回滚。

3. 执行流程

  1. 线程 A

    • 触发当前读,匹配 name = 'a' 的行,加排他锁,将其修改为 name = 'b'(未提交)。
    • 锁未释放,数据仅存在于内存中。
  2. 线程 B

    • 触发当前读,读取到线程 A 未提交的 name = 'b',匹配 WHERE name = 'b'
    • 尝试加排他锁,因线程 A 已持有锁而进入阻塞状态,等待锁释放。

4. 结果取决于线程 A 的操作

情况分类线程 A 操作线程 B 操作流程最终 name 值核心原因分析
情况 1先提交1. 阻塞结束,获取锁
2. 当前读匹配 name = 'b',修改为 'c'
3. 提交事务
   'c'线程 A 的修改生效,线程 B 基于 'b' 进一步修改
情况 2先回滚1. 阻塞结束,获取锁
2. 当前读发现 name = 'a',条件不匹配,无修改
3. 提交事务
  'a'线程 A 的修改撤销,线程 B 的 WHERE 条件不成立,未执行修改
情况 3(不可能发生)未提交 / 未回滚/(线程b先提交)因未获取锁处于阻塞状态,UPDATE 未执行,无法提交事务     无结果线程 B 需等待线程 A 释放锁才能执行,无法抢先提交

5. 关键点总结

  1. 当前读的可见性

    • 线程 B 的 UPDATE 能看到线程 A 未提交的修改(name = 'b'),因此匹配条件并尝试加锁。
  2. 锁的阻塞机制

    • 线程 B 必须等待线程 A 释放锁,无法抢先提交事务。
  3. 事务原子性

    • 线程 A 的提交 / 回滚决定最终数据的基础版本,线程 B 的修改依赖于此。
对比场景:若线程 B 查询 SELECT * FROM 表 WHERE name = 'b'
  • 普通 SELECT(快照读):看不到线程 A 未提交的修改,返回空结果。
  • SELECT ... FOR UPDATE(当前读):会阻塞等待线程 A 释放锁,锁释放后返回 name = 'b'(若 A 提交)或空(若 A 回滚)。

6. 实践建议

  1. 避免长事务:长时间持有锁会增加阻塞概率。
  2. 优化查询条件:确保 UPDATE 的 WHERE 条件使用索引,减少锁范围。
  3. 处理阻塞异常:业务代码需考虑锁等待超时的情况(如设置 innodb_lock_wait_timeout)。

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

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

相关文章

css样式中的选择器和盒子模型

目录 一、行内样式二、内部样式三、外部样式四、结合选择器五、属性选择器六、包含选择器七、子选择器八、兄弟选择器九、选择器组合十、伪元素选择器十一、伪类选择器十二、盒子模型 相关文章 学习标签、属性、选择器和外部加样式积累CSS样式属性:padding、marg…

关于基于lvgl库做的注册登录功能的代码步骤:

以下是完整的文件拆分和代码存放说明,按功能模块化划分,方便工程管理:一、需要创建的文件清单 文件名 作用 类型 main.c 程序入口,初始化硬件和LVGL 源文件 ui.h 声明界面相关函数 头文件 ui.c 实现登录、注册、主页面的UI 源文…

RAII机制以及在ROS的NodeHandler中的实现

好的,这是一个非常核心且优秀的设计问题。我们来分两步详细解析:先彻底搞懂什么是 RAII,然后再看 ros::NodeHandle 是如何巧妙地运用这一机制的。1. 什么是 RAII 机制? RAII 是 “Resource Acquisition Is Initialization” 的缩写…

Linux LVS集群技术

LVS集群概述1、集群概念1.1、介绍集群是指多台服务器集中在一起,实现同一业务,可以视为一台计算机。多台服务器组成的一组计算机,作为一个整体存在,向用户提供一组网络资源,这些单个的服务器就是集群的节点。特点&…

spring-ai-alibaba如何上传文件并解析

问题引出 在我们日常使用大模型时,有一类典型的应用场景,就是将文件发送给大模型,然后由大模型进行解析,提炼总结等,这一类功能在官方app中较为常见,但是在很多模型的api中都不支持,那如何使用…

「双容器嵌套布局法」:打造清晰层级的网页架构设计

一、命名与核心概念 “双容器嵌套布局法”,核心是通过两层容器嵌套构建网页结构:外层容器负责控制布局的“宏观约束”(如页面最大宽度、背景色等),内层容器聚焦“微观排版”(内容居中、内边距调整、红色内容…

基于深度学习的自然语言处理:构建情感分析模型

前言 自然语言处理(NLP)是人工智能领域中一个非常活跃的研究方向,它致力于使计算机能够理解和生成人类语言。情感分析(Sentiment Analysis)是NLP中的一个重要应用,其目标是从文本中识别和提取情感倾向&…

JWT原理及利用手法

JWT 原理 JSON Web Token (JWT) 是一种开放的行业标准,用于在系统之间以 JSON 对象的形式安全地传输信息。这些信息经过数字签名,因此可以被验证和信任。其常用于身份验证、会话管理和访问控制机制中传递用户信息。 与传统的会话令牌相比,JWT…

DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar),日历_睡眠记录日历示例(CalendarView01_30)

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录DeepS…

git的diff命令、Config和.gitignore文件

diff命令:比较git diff xxx:工作目录 vs 暂存区(比较现在修改之后的工作区和暂存区的内容)git diff --cached xxx:暂存区 vs Git仓库(现在暂存区内容和最一开始提交的文件内容的比较)git diff H…

Linux中的LVS集群技术

一、实验环境(RHEL 9)1、NAT模式的实验环境主机名IP地址网关网络适配器功能角色client172.25.254.111/24(NAT模式的接口)172.25.254.2NAT模式客户机lvs172.25.254.100/24(NAT模式的接口)192.168.0.100/24&a…

【数据结构】「队列」(顺序队列、链式队列、双端队列)

- 第 112篇 - Date: 2025 - 07 - 20 Author: 郑龙浩(仟墨) 文章目录队列(Queue)1 基本介绍1.1 定义1.2 栈 与 队列的区别1.3 重要术语2 基本操作3 顺序队列(循环版本)两种版本两种版本区别版本1.1 - rear指向队尾后边 且 无 size …

Java行为型模式---解释器模式

解释器模式基础概念解释器模式(Interpreter Pattern)是一种行为型设计模式,其核心思想是定义一个语言的文法表示,并定义一个解释器,使用该解释器来解释语言中的句子。这种模式将语法解释的责任分开,使得语法…

[spring6: PointcutAdvisor MethodInterceptor]-简单介绍

Advice Advice 是 AOP 联盟中所有增强(通知)类型的标记接口,表示可以被织入目标对象的横切逻辑,例如前置通知、后置通知、异常通知、拦截器等。 package org.aopalliance.aop;public interface Advice {}BeforeAdvice 前置通知的标…

地图定位与导航

定位 1.先申请地址权限(大致位置精准位置) module.json5文件 "requestPermissions": [{"name": "ohos.permission.INTERNET" },{"name": "ohos.permission.LOCATION","reason": "$string:app_name",&qu…

【数据结构】揭秘二叉树与堆--用C语言实现堆

文章目录1.树1.1.树的概念1.2.树的结构1.3.树的相关术语2.二叉树2.1.二叉树的概念2.2.特殊的二叉树2.2.1.满二叉树2.2.2.完全二叉树2.3.二叉树的特性2.4.二叉树的存储结构2.4.1.顺序结构2.4.2.链式结构3.堆3.1.堆的概念3.2.堆的实现3.2.1.堆结构的定义3.2.2.堆的初始化3.2.3.堆…

区间树:多维数据的高效查询

区间树:多维数据的高效查询 大家好,今天我们来探讨一个在计算机科学中非常有趣且实用的数据结构——区间树。想象一下,你是一位城市规划师,需要快速找出某个区域内所有的医院、学校或商场。或者你是一位游戏开发者,需要…

SQL 魔法:LEFT JOIN 与 MAX 的奇妙组合

一、引言 在数据库操作的领域中,数据的关联与聚合处理是核心任务之一。LEFT JOIN作为一种常用的连接方式,能够将左表中的所有记录与右表中满足连接条件的记录进行关联,即便右表中没有匹配的记录,左表的记录也会被保留,…

手写tomcat

package com.qcby.annotation;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;Target(ElementType.TYPE)// 表示该注解只能用于类上 Retention(Retentio…

Android平台下openssl动态库编译

1. 下载Linux平台下的NDK软件包 NDK 下载 | Android NDK | Android Developers 下载完成后执行解压命令 # unzip android-ndk-r27d-linux.zip 2. 下载openssl-1.1.1w源码包,并解压 # tar -xzvf openssl-1.1.1w.tar.gz 3. 进入解压后的openssl-1.1.1w目录 …