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

当前读和快照读

概述

特性 快照读 (Snapshot Read) 当前读 (Current Read)
核心原理 基于 MVCC 和多版本数据 基于 机制
读取内容 历史版本数据(某个时间点的快照) 数据的最新已提交版本
是否加锁 不加锁(非阻塞) 加锁(S锁或X锁)
实现方式 普通的 SELECT 语句 SELECT ... FOR UPDATE, SELECT ... LOCK IN SHARE MODE, UPDATE, DELETE, INSERT
隔离级别 在 RC 和 RR 级别下生效 所有隔离级别都适用
一致性 一致性非锁定读 锁定读

一、快照读 (Snapshot Read)

1. 定义
快照读是指 InnoDB 使用 多版本控制 (MVCC) 机制,为查询呈现一个基于某个时间点的数据库快照的读取方式。它读取的不是数据的最新状态,而是记录的一个历史版本。

2. 如何工作

  • 当一个事务执行快照读(如 SELECT * FROM table;)时,InnoDB 会为该事务生成一个 Read View(读视图)。
  • 通过这个 Read View,结合数据行中的 DB_TRX_ID(事务ID)和 DB_ROLL_PTR(回滚指针)在 Undo Log 中形成的版本链,InnoDB 可以找到对这个事务可见的那个版本的数据。
  • 正如上一个问题中举例的那样,它可能会跳过由未提交事务或在本事务开始之后才提交的事务所做的修改。

3. 特点

  • 不加锁:这是快照读最大的优点,它使得读操作不会阻塞写操作,写操作也不会阻塞读操作,极大地提高了数据库的并发性能。
  • 非阻塞:读取操作无需等待任何锁的释放。
  • 依赖隔离级别
    • REPEATABLE READ (可重复读):在第一次执行快照读时生成 Read View,后续所有快照读都复用这个 Read View。因此,在整个事务过程中,每次读到的都是同一个一致性快照,实现了可重复读。
    • READ COMMITTED (读已提交):在每次执行快照读时都会生成一个新的 Read View。因此,每次读都能看到最新已提交的数据,但不可重复读。

4. 示例

-- 假设隔离级别是 REPEATABLE READ
START TRANSACTION; -- 事务开始-- T1时刻:第一次快照读,生成ReadView
SELECT * FROM users WHERE id = 1; -- 返回 balance = 1000-- 在此期间,另一个事务提交了:UPDATE users SET balance = 900 WHERE id = 1;-- T2时刻:第二次快照读,复用T1时刻的ReadView
SELECT * FROM users WHERE id = 1; -- 仍然返回 balance = 1000 (可重复读)COMMIT;

在这个例子中,尽管数据已经被其他事务修改,但第二个 SELECT 仍然返回和第一个相同的结果,因为它读取的是快照,而不是最新数据。


二、当前读 (Current Read)

1. 定义
当前读是指读取数据的最新已提交版本,并且为了保证在读取过程中数据不被其他事务修改,会对读取的记录加锁

2. 如何工作

  • 当前读通过给记录加锁来实现。
    • SELECT ... LOCK IN SHARE MODE 会加一个 S锁(共享锁)。
    • SELECT ... FOR UPDATEUPDATEDELETEINSERT 会加 X锁(排他锁)。
  • 加锁后,其他事务如果想修改这条记录(需要X锁),或者也想用 SELECT ... FOR UPDATE 来读取它,就会被阻塞,直到当前事务释放锁。

3. 特点

  • 加锁:这是当前读的核心,通过锁来保证数据的一致性。
  • 读取最新数据:它总是读取记录已提交的最新版本,而不是历史快照。
  • 会阻塞/被阻塞:因为涉及锁的竞争,当前读操作可能会被其他事务的锁阻塞,也可能会阻塞其他事务。
  • 解决并发问题:当前读是解决“丢失更新”等问题的关键手段。例如,在并发转账场景中,必须先通过 SELECT ... FOR UPDATE 当前读获取最新的余额并加锁,然后再进行更新,否则可能发生覆盖。

4. 示例:经典的并发扣款场景

START TRANSACTION;-- 使用当前读,获取id=1的用户的最新余额,并为其加上X锁(排他锁)
-- 这会阻止其他事务也使用当前读或修改这条记录
SELECT balance FROM users WHERE id = 1 FOR UPDATE;-- 应用程序中计算:new_balance = current_balance - 100
-- 基于当前读到的、最新的、且已被锁定的数据进行更新
UPDATE users SET balance = new_balance WHERE id = 1;COMMIT; -- 提交事务,释放锁

如果不使用 FOR UPDATE,两个事务可能同时快照读到相同的余额(例如1000),然后各自计算并更新(900和900),最终结果(900)是错误的,因为有一笔扣款被丢失了。当前读通过加锁确保了操作的串行化。


三、重要区别与联系

  1. 默认行为:单纯的 SELECT 语句默认是快照读,而 UPDATEDELETEINSERT 等写操作默认是当前读UPDATE 操作的过程其实是:先当前读找到要更新的记录并加锁,然后修改数据。

  2. 解决不同的问题

    • 快照读 解决了读-写并发冲突,提升了数据库的读并发能力。
    • 当前读 解决了写-写并发冲突,保证了数据更新的正确性。
  3. 组合使用:在一个事务中,可以混合使用快照读和当前读。

    START TRANSACTION;-- 快照读:查看大致情况,不加锁
    SELECT * FROM orders; -- 当前读:决定要处理某个订单时,用当前读锁定它,防止别人修改
    SELECT * FROM orders WHERE id = 123 FOR UPDATE;-- ... 处理业务逻辑 ...UPDATE orders SET status = 'processed' WHERE id = 123;
    COMMIT;
    

总结

操作类型 语句示例 读类型 说明
快照读 SELECT * FROM table; 历史数据 基于MVCC,不加锁,实现非阻塞读
当前读 SELECT * FROM table LOCK IN SHARE MODE; 最新数据 加S锁(共享锁)
SELECT * FROM table FOR UPDATE; 最新数据 加X锁(排他锁)
UPDATE table ... 最新数据 先当前读加X锁,再修改
DELETE FROM table ... 最新数据 先当前读加X锁,再删除
INSERT INTO table ... - 会对新插入的数据加X锁(隐式)
http://www.sczhlp.com/news/52885/

相关文章:

  • 重庆放心seo整站优化番禺网站开发哪家强
  • 做网站美工未来规划东城网站开发公司
  • 网站建设的总结100字改网站标题
  • 有哪些游戏可以做网站好的企业管理网站
  • 重庆网站制作公司多少钱网络建设合同
  • 做视频网站源码顺德网站建设
  • 杭州模板建站代理three.js 做的网站
  • 做网站 博客wordpress mysql端口
  • 做网站怎么添加关键词深圳seo关键词优化
  • 使用GPT-SoVITS克隆任意角色的声音
  • 0115_建造者模式(Builder)
  • Consul入门--Window
  • 网站配色的原理和方法商城app定制开发
  • Js 手写 Promise 完整实现
  • 网站开发语言排行榜网站改版应该怎么做
  • 用ip的网站要备案吗网络优化软件哪个好
  • 电子商务网站建设首页流程啥是深圳网站定制开发
  • 凡科网站源码下载php 手机网站 模板
  • 内心的冲动和精力的矛盾
  • 20220719_QQ群_KCS1_OAEP模式RSA解密
  • 优化网站做内链接WordPress动画随音乐变化
  • 可以做网站首页的图片素材北京装修公司全包价格
  • 有什么网站可以做试题dedecms公司网站怎么做
  • 正规的国内网站建设公司好的平面设计灵感网站
  • 免费php企业网站wordpress干什么用的
  • 服务器网站建设教程视频教程怎样在网上卖东西步骤
  • metro风格网站模板网站备案信息加到哪里
  • 荣成网站制作公司网站建设的必要性分析
  • 外贸网站外链平台模板网站开发注意事项
  • 怎么导入视频到wordpress北京优化seo排名优化