MySQL 三大并发问题与事务隔离级别一、三大并发问题数据库在高并发环境下多个事务同时执行可能会产生数据一致性问题主要包括问题描述场景脏读Dirty Read读取到了其他事务未提交的数据事务 A 修改数据但未提交事务 B 读取到了该修改后的数据不可重复读Non-Repeatable Read同一个事务内两次读取同一行数据结果不同事务 A 第一次读取某行数据事务 B 修改并提交该行事务 A 再次读取发现数据变化幻读Phantom Read同一个事务内两次查询结果集的行数不同事务 A 根据条件查询事务 B 插入/删除满足条件的数据并提交事务 A 再次查询发现结果集变化不可重复读 vs 幻读问题关注点不可重复读同一行数据内容发生变化幻读结果集行数发生变化简单理解不可重复读别人修改了一条数据幻读别人新增或删除了一批符合条件的数据二、四种事务隔离级别事务隔离级别从低到高隔离级别脏读不可重复读幻读实现机制READ UNCOMMITTED读未提交✅允许✅允许✅允许不加锁直接读取最新数据READ COMMITTED读已提交❌禁止✅允许✅允许每次查询生成新的 ReadViewMVCCREPEATABLE READ可重复读❌禁止❌禁止⚠️基本禁止事务开始生成 ReadView并复用SERIALIZABLE串行化❌禁止❌禁止❌禁止所有操作加锁完全串行执行注意MySQL InnoDB 的 RRRepeatable Read通过MVCC Gap Lock间隙锁基本解决幻读。但极端情况下仍可能出现幻读例如当前读SELECT … FOR UPDATE未正确使用锁机制三、READ UNCOMMITTED读未提交设置SETSESSIONTRANSACTIONISOLATIONLEVELREADUNCOMMITTED;特点不加任何锁直接读取数据页最新内容性能最高数据一致性最差问题无法避免脏读不可重复读幻读使用场景实际业务中几乎不会使用。四、READ COMMITTED读已提交Oracle 默认隔离级别设置SETSESSIONTRANSACTIONISOLATIONLEVELREADCOMMITTED;特点每次执行 SELECT 时都会生成新的 ReadView只能读取已经提交的数据优点解决✅ 脏读缺点由于每次查询 ReadView 不同可能出现同一个事务内多次读取同一数据结果不同即❌ 不可重复读示例事务 ASELECTmoneyFROMaccountWHEREid1;读取money 100事务 BUPDATEaccountSETmoney200WHEREid1;COMMIT;事务 A 再次查询money 200产生不可重复读。适用场景互联网业务中较常见对一致性要求不是极端严格希望降低锁竞争提高并发性能五、REPEATABLE READ可重复读MySQL InnoDB 默认隔离级别设置SETSESSIONTRANSACTIONISOLATIONLEVELREPEATABLEREAD;特点事务开始时生成 ReadView事务期间一直复用该 ReadView因此同一个事务内多次读取同一数据结果保持一致。解决✅ 脏读✅ 不可重复读同时通过MVCCGap Lock间隙锁解决幻读。六、MVCC 实现原理MVCCMulti-Version Concurrency Control多版本并发控制MySQL InnoDB 每行数据隐藏两个字段隐藏字段作用DB_TRX_ID最后修改该行数据的事务 IDDB_ROLL_PTR回滚指针指向 undo log七、ReadView 结构ReadView 包含字段含义creator_trx_id创建该 ReadView 的事务 IDup_limit_id当前活跃事务中最小事务 IDlow_limit_id下一个即将分配的事务 IDtrx_ids当前活跃事务 ID 列表八、MVCC 可见性判断规则判断当前版本是否可见if DB_TRX_ID creator_trx_id: 可见自己修改的数据 if DB_TRX_ID up_limit_id: 可见事务已经提交 if DB_TRX_ID low_limit_id: 不可见未来事务产生的数据 if up_limit_id DB_TRX_ID low_limit_id: if DB_TRX_ID 在 trx_ids 中: 不可见事务仍然活跃 else: 可见事务已经提交九、SERIALIZABLE串行化设置SETSESSIONTRANSACTIONISOLATIONLEVELSERIALIZABLE;特点最高隔离级别。规则SELECT 自动加共享锁S锁UPDATE / DELETE / INSERT 加排他锁X锁效果所有事务串行执行。优点数据一致性最高。缺点并发能力最低性能最差适用金融对账强一致业务十、隔离级别查看与设置查看当前隔离级别MySQL 8.0SELECTtransaction_isolation;MySQL 5.7SELECTtx_isolation;设置当前会话隔离级别SETSESSIONTRANSACTIONISOLATIONLEVELREPEATABLEREAD;设置全局隔离级别SETGLOBALTRANSACTIONISOLATIONLEVELREADCOMMITTED;全局设置只影响新创建的连接。十一、RC 与 RR 对比场景事务A: 开始 ↓ 读取 x1 ↓ 事务B: 修改 x2 提交 ↓ 再次读取 x ↓ 提交READ COMMITTED结果第一次读取 x 1 第二次读取 x 2产生不可重复读原因每次 SELECT 创建新的 ReadViewREPEATABLE READ结果第一次读取 x 1 第二次读取 x 1原因整个事务复用同一个 ReadView十二、面试高频问题问题答案MySQL 默认隔离级别REPEATABLE READRROracle 默认隔离级别READ COMMITTEDRCRR 是否完全解决幻读否普通快照读解决当前读需要 Gap Lock为什么互联网公司常使用 RC减少锁冲突提高并发性能RR 有什么问题间隙锁可能增加死锁概率MVCC 为什么不用加锁通过 ReadView undo log 构造历史版本实现读写不阻塞十三、总结隔离级别核心特点READ UNCOMMITTED性能最高但数据最不安全READ COMMITTED每次读取最新已提交数据REPEATABLE READMySQL 默认通过 MVCC 保证一致性SERIALIZABLE强一致但并发最低记忆RU 什么都不管 RC 每次重新看 RR 一直看同一个快照 Serializable 排队执行