网站建设报告书廊坊网站建设-商昊网络
2026/1/14 2:40:11 网站建设 项目流程
网站建设报告书,廊坊网站建设-商昊网络,wordpress选图框,动态域名可以做网站吗MySQL 事务隔离级别详解 关键词#xff1a;隔离级别、脏读、不可重复读、幻读、MVCC、间隙锁。 重点#xff1a;搞清楚四个隔离级别分别“允许/禁止”哪些现象#xff0c;以及 InnoDB 实际是怎么做的。 一、为什么需要事务隔离#xff1f; 在数据库里#xff0c;多个事务…MySQL 事务隔离级别详解关键词隔离级别、脏读、不可重复读、幻读、MVCC、间隙锁。重点搞清楚四个隔离级别分别“允许/禁止”哪些现象以及 InnoDB 实际是怎么做的。一、为什么需要事务隔离在数据库里多个事务是并发执行的一个事务在读数据另一个事务在改数据还有一个事务在插入/删除数据。如果完全不隔离你可能读到别人还没提交的修改脏读同一个事务里两次读同一行结果却不同不可重复读同一个事务里两次按条件查询前后出现的行数不一样幻读。事务隔离级别就是在“读到最新数据” 和 “读到稳定一致的数据” 以及 “系统性能” 之间做平衡。SQL 标准定义了 4 个隔离级别对应不同的安全性和性能取舍。二、三种典型并发现象先搞清楚几个常见“坏现象”是什么。2.1 脏读Dirty Read事务 A 读取到了事务 B尚未提交的修改如果 B 后面回滚了A 读到的就是“根本没生效过的假数据”。示意T1: 事务 BUPDATE account SET balance balance - 100 WHERE id 1; T2: 事务 ASELECT balance FROM account WHERE id 1; -- 读到了减少 100 后的值 T3: 事务 BROLLBACK;此时事务 A 读到的就是“脏数据”。2.2 不可重复读Non-Repeatable Read同一个事务中两次读取同一行数据结果不一样原因是两次读取之间别的事务提交了对该行的修改。示意T1: 事务 ASELECT balance FROM account WHERE id 1; -- 读到 1000 T2: 事务 BUPDATE account SET balance 800 WHERE id 1; COMMIT; T3: 事务 A再次 SELECT balance FROM account WHERE id 1; -- 读到 800对于一部分业务来说“同一个事务里两次查应该一致”是刚性需求。2.3 幻读Phantom Read同一个事务中两次按某个条件查询结果的行数不一样原因是两次查询之间有别的事务插入/删除了满足条件的行。示意T1: 事务 ASELECT * FROM order WHERE amount 100; -- 结果 5 行 T2: 事务 BINSERT INTO order(id, amount) VALUES(100, 200); COMMIT; T3: 事务 A再次 SELECT * FROM order WHERE amount 100; -- 结果 6 行对于“统计 校验”等场景这种“幻影数据”可能会搞乱逻辑。三、四种事务隔离级别SQL 标准SQL 标准定义了 4 个隔离级别READ UNCOMMITTED读未提交READ COMMITTED读已提交REPEATABLE READ可重复读SERIALIZABLE可串行化它们从“弱到强”的对应关系是READ UNCOMMITTED READ COMMITTED REPEATABLE READ SERIALIZABLE隔离越强读到的数据越“稳定一致”并发性能通常越差。3.1 READ UNCOMMITTED读未提交特点可以读到别的事务尚未提交的修改性能最高但数据安全性最差。存在问题✅ 脏读可能✅ 不可重复读可能✅ 幻读可能。这个隔离级别一般不会在生产中使用。3.2 READ COMMITTED读已提交特点每一次查询都只能看到已经提交的最新数据每次 SELECT 都会生成一个新的“视图”。效果❌ 脏读被禁止✅ 不可重复读依然可能✅ 幻读依然可能。示意事务 A SELECT balance FROM account WHERE id 1; -- 第一次读 事务 B UPDATE account SET balance 800 WHERE id 1; COMMIT; 事务 A SELECT balance FROM account WHERE id 1; -- 第二次读看到 800两次读到的结果可能不同因此称为“读已提交”而不是“可重复读”。在很多商业数据库如 Oracle中默认隔离级别就是 READ COMMITTED。3.3 REPEATABLE READ可重复读特点一个事务从开始到结束看到的数据是一致的“快照”同一事务中多次读同一行结果保持一致MySQL InnoDB 的默认隔离级别。效果❌ 脏读禁止❌ 不可重复读禁止对同一行✅ 幻读按照 SQL 标准定义理论上仍可能。但是InnoDB 在 REPEATABLE READ 下配合MVCC 间隙锁/Next-Key Lock在大多数场景下也能避免幻读只是在严格定义上仍认为“幻读可能存在某些边界情况”。示意事务 ARR 第一次 SELECT * FROM t WHERE id 1; -- 读到旧版本 事务 B UPDATE t SET ... WHERE id 1; COMMIT; -- 提交新值 事务 A 第二次 SELECT * FROM t WHERE id 1; -- 仍然读到第一次看到的版本因为 A 的“视图”是在事务开始时创建的后续读都以这个视图为准。3.4 SERIALIZABLE可串行化特点最高隔离级别强制所有事务看起来像是顺序执行的通常通过对读也加锁类似范围锁/表锁来实现。效果❌ 脏读禁止❌ 不可重复读禁止❌ 幻读禁止。代价是并发能力大幅下降在高并发场景下一般不建议使用。四、MySQL InnoDB 中的实际实现细节4.1 全局 / 会话隔离级别查看当前隔离级别MySQL 8.0SELECTtransaction_isolation;-- 或SELECTglobal.transaction_isolation;设置隔离级别-- 设置全局隔离级别SETGLOBALtransaction_isolationREPEATABLE-READ;-- 设置当前会话隔离级别SETSESSIONtransaction_isolationREAD-COMMITTED;MySQL 5.x 常用写法已逐渐被替换SELECTtx_isolation;SETSESSIONtx_isolationREAD-COMMITTED;InnoDB 默认隔离级别REPEATABLE READ。4.2 READ COMMITTED vs REPEATABLE READ差别在哪核心差别在于一致性视图Read View创建时机READ COMMITTED每次 SELECT 都会生成一个新的 Read View因此每次查询都能看到当前已经提交的最新版本故容易出现“不可重复读”。REPEATABLE READ在事务第一次读取数据时创建 Read View整个事务期间都复用同一个 Read View后续再读同一行看到的仍然是第一次看到的版本避免了不可重复读。这就是 InnoDB 利用MVCC多版本并发控制做出不同隔离语义的核心。4.3 幻读与间隙锁 / Next-Key Lock为了控制“幻读”InnoDB 在可重复读级别下对范围查询 锁定读SELECT ... FOR UPDATE / FOR SHARE会加间隙锁Gap Lock锁定某个区间禁止在区间内插入新行Next-Key Lock记录锁 间隙锁的组合锁[前一个值, 当前值]区间。这样一个事务在某个范围上进行锁定读或修改另一个事务就没法往这个范围内插入新记录从而在多数情况下避免了“我查询某条件范围后面新插入的记录突然冒出来”的幻读问题。不过对纯查询普通 SELECT 不加锁来说避免幻读主要是通过 MVCC 来实现“读到一个旧快照”对加锁读来说则通过 Next-Key Lock Gap Lock 尽量避免幻读。五、各隔离级别与并发现象对照表用一个表总览一下隔离级别脏读Dirty Read不可重复读Non-Repeatable幻读PhantomREAD UNCOMMITTED✅ 可能✅ 可能✅ 可能READ COMMITTED❌ 禁止✅ 可能✅ 可能REPEATABLE READ*❌ 禁止❌ 禁止✅ 理论上可能*SERIALIZABLE❌ 禁止❌ 禁止❌ 禁止说明标准语义下REPEATABLE READ 仍可能有幻读。InnoDB 在 REPEATABLE READ 间隙锁/Next-Key Lock 下大部分实际场景中也能避免幻读。六、怎么选隔离级别实践建议绝大多数业务用默认的 REPEATABLE READ 就够了InnoDB 默认是 REPEATABLE READ配合 MVCC 和 Next-Key Lock能很好平衡一致性和性能。如果有强烈的“读最新”需求可以考虑 READ COMMITTED例如某些业务要求一旦事务 B 提交我的后续读立刻能看到它不介意“同一事务内两次读同一行不一样”。SERIALIZABLE 一般只在一致性要求极端高且并发不大的系统里使用比如一些对账、结算、强一致金融场景否则容易把并发性能打爆。READ UNCOMMITTED 几乎没有场景需要基本不要用七、面试/复习高频问答小抄Q1MySQL 默认的事务隔离级别是什么InnoDB 默认是REPEATABLE READ可重复读。Q2四个隔离级别分别解决/遗留了哪些问题READ UNCOMMITTED什么问题都不解决允许脏读READ COMMITTED解决脏读不可重复读、幻读仍存在REPEATABLE READ解决脏读 不可重复读幻读理论上仍可能SERIALIZABLE理论上解决所有问题但性能最差。Q3READ COMMITTED 和 REPEATABLE READ 的实现差别READ COMMITTED每次 SELECT 都新建一个 Read ViewREPEATABLE READ事务第一次 SELECT 时创建 Read View后续复用都依赖 MVCC多版本并发控制。Q4InnoDB 如何处理幻读利用MVCC提供一致性视图使得查询看到的是历史快照配合间隙锁Gap Lock、Next-Key Lock在加锁读和更新场景中尽量避免其他事务在范围内插入新行。Q5如何查看和设置当前隔离级别-- 查看SELECTtransaction_isolation;-- 设置当前会话SETSESSIONtransaction_isolationREAD-COMMITTED;八、小结事务隔离级别是用来控制并发读写时“看见什么”的规则集合MySQL/InnoDB 提供四个级别读未提交、读已提交、可重复读、可串行化实现手段主要有MVCC多版本并发控制解决大部分读写并发问题行锁 间隙锁 Next-Key Lock控制并发写和“范围插入”日常绝大部分情况用 InnoDB 默认的 REPEATABLE READ 就足够极端需要读最新且能接受不可重复读时用 READ COMMITTED。理解了“隔离级别 看见哪些版本的数据 加哪些锁”你基本就把 MySQL 事务隔离级别的本质吃透了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询