资讯动态

MYSQL 事务原理

发布时间:2026/8/9 6:58:41 来源:尧图企业网站定制
脏读一个事务读到了另一个事务尚未提交的修改。连接1连接2连接1事务未提交但是连接2可以读到其修改。将隔离级别设置为read commited (读已提交) 可以解决脏读。不可重复读同一事务里两次读同一行结果不一样。原因是中间有别的事务提交了。将隔离级别设置为repeatable read (可重复读) 可以解决不可重复读。幻读同一事务里两次读取同一个范围内的记录得到的结果集不同。当前读和快照读不一样。在repeatable级别通过加锁解决幻读问题连接1连接2连接2若想插入会阻塞等待。当连接1 commit或rollback才会执行。read uncommited : 脏读、不可重复读、幻读。read commited : 不可重复读、幻读。repeatable read : 幻读。MVCC 是什么MVCC Multi-Version Concurrency Control多版本并发控制核心想法一行数据不只留 当前值还会保留历史版本。读的时候尽量读某个历史版本写的时候生成新版本这样读写常常不用互相锁死。可以把它想成一行记录有一条 版本链当前版本 (trx100, balance300)↑ undo旧版本 (trx80, balance200)↑ undo更旧版本 (trx50, balance100)更新时写出新版本旧值放到 undo log串成链普通SELECT快照读沿版本链往回找找到「自己可见」的那个版本SELECT ... FOR UPDATE当前读读最新已提交/需要加锁的版本走锁不完全靠这套纯快照逻辑。Read View 是什么Read View读视图 是事务做一致性读时InnoDB 生成的一份「可见性规则快照」。它回答的问题只有一个版本链上这个版本当前事务能不能看见判断逻辑直观理解版本由已提交且在我视野之前的事务产生 → 可见版本由我自己产生 → 可见版本由生成 Read View 时还未提交的事务产生 → 不可见继续沿 undo 找更老版本版本由比我视野更晚的事务产生 → 不可见找到第一个可见版本就是这次SELECT的结果。READ COMMITTED每次普通SELECT新建一个 Read View所以中间别人COMMIT了下一次查可能看到新值可能不可重复读、幻读REPEATABLE READ事务里第一次普通SELECT创建 Read View之后复用所以同一事务里多次普通查询视野不变可重复读普通SELECT也很难看到新插入的「幻行」隔离级别差异很大程度上就是 Read View 创建时机不同每次读新建 vs 事务内复用在 InnoDB 里读分两种快照读一致性读读的是 Read View 下可见的历史版本一般不加锁或几乎不挡别人写。常见语句SELECT * FROM accounts WHERE id 1;特点走 MVCC Read ViewRR 下同一事务多次读结果通常一致可能不是磁盘上「此刻最新已提交」的那一版当前读读的是 最新版本并且会加锁保证读到的行别人不能随便改。常见语句SELECT ... FOR UPDATE; SELECT ... LOCK IN SHARE MODE; -- 或 FOR SHARE UPDATE / DELETE; -- 先当前读再改 INSERT ... SELECT ...; -- 其中的 SELECT 也可能是当前读特点不靠「复用旧 Read View」来读旧版本要加行锁 / 间隙锁等能读到最新已提交数据并锁住防止并发冲突MySQL 锁机制详解MySQL 锁├── 表级锁表锁、意向锁、MDL└── 行级锁InnoDB 主力├── 模式共享锁 S / 排他锁 X└── 范围记录锁 Record / 间隙锁 Gap / 临键锁 Next-Key行锁的两种模式S 和 X锁含义常见语句共享锁 S允许别人再加 S不允许加 XSELECT ... FOR SHARE排他锁 X不允许别人再加 S/XSELECT ... FOR UPDATE、UPDATE、DELETE兼容关系很简单S 与 S兼容S 与 X不兼容X 与 X不兼容所以A 持有某行 X 锁时B 再对同行FOR UPDATE→ B 等待A 只是普通SELECT快照读→ 通常不持有行锁B 的更新不一定被它堵住行锁的三种范围Record / Gap / Next-Key这是 InnoDB 锁最核心的部分。1. 记录锁Record Lock锁住已经存在的索引记录。SELECT * FROM accounts WHERE id 1 FOR UPDATE;效果锁住id1这一行防止别人改/删它。2. 间隙锁Gap Lock锁住索引记录之间的空隙不锁某行本身但阻止别人往空隙里插入。例如索引上有id 10, 20间隙(10, 20)被锁后INSERT INTO t VALUES (15, ...); -- 可能被堵住间隙锁的主要意义防止幻读当前读场景下别插进新行。3. 临键锁Next-Key LockNext-Key Lock Record Lock Gap LockInnoDB 在 REPEATABLE READ 下当前读默认常用这套算法锁住一个左开右闭区间例如(10, 20]。既防止改20也防止在10和20之间插入新记录。快照读 vs 当前读这是理解「锁」和「MVCC」分工的关键。快照读SELECT * FROM accounts WHERE id 1;读的是 Read View 下可见的历史版本一般不加行锁RR 下同一事务多次普通查询结果通常稳定当前读SELECT * FROM accounts WHERE id 1 FOR UPDATE; UPDATE accounts SET balance 200 WHERE id 1; DELETE FROM accounts WHERE id 1;读最新数据加锁可能阻塞其他事务的冲突写/插隔离级别如何影响锁隔离级别简要特征READ UNCOMMITTED可脏读基本不用于生产READ COMMITTED每次普通 SELECT 新 Read View当前读主要是记录锁间隙锁很少REPEATABLE READ默认快照复用当前读大量使用 Next-Key防幻读更强SERIALIZABLE普通 SELECT 也会趋向加锁读并发最差、最严格大多数业务用默认 RR 就够若热点行冲突严重、且能接受不可重复读可评估 RC不要为了“更安全”一上来就 SERIALIZABLE

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价