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

MySQL事务隔离级别详解

MySQL 事务隔离级别详解记得刚入职的时候线上出了个诡异的 bug用户 A 给自己账户充值了 100 块结果余额没变。查了半天发现是事务隔离级别没搞懂导致一个事务读到了另一个事务未提交的数据。今天咱们就来彻底搞懂 MySQL 的事务隔离级别看完这篇你就能避开 90% 的事务坑。事务的 ACID 是啥先铺垫一下事务有四大特性记住这个面试必问AAtomicity原子性事务要么全做要么全不做不可能只执行一半CConsistency一致性事务执行前后数据库都得是合法的状态IIsolation隔离性多个事务并发执行彼此之间不能互相干扰DDurability持久性事务提交后数据就得永久保存哪怕数据库宕机今天重点是I隔离性也就是隔离级别。没有隔离级别会出啥问题如果多个事务完全不隔离会有三种经典问题1. 脏读Dirty Read事务 A 读到了事务 B未提交的数据。如果事务 B 后面回滚了那事务 A 读到的就是脏数据。时间轴 T1: 事务A开始 T2: 事务B开始 T3: 事务B把小明余额从100改成200未提交 T4: 事务A读取小明余额读到200 ← 脏读 T5: 事务B回滚小明余额变回100 T6: 事务A拿着200去干活实际上余额只有1002. 不可重复读Non-Repeatable Read同一个事务内两次读取同一行数据结果不一样因为别的事务修改并提交了这行数据。时间轴 T1: 事务A开始读取小明余额100 T2: 事务B开始把小明余额改成200提交 T3: 事务A再次读取小明余额200 ← 不可重复读3. 幻读Phantom Read同一个事务内两次执行同样的查询记录数量不一样因为别的事务插入或删除了数据。时间轴 T1: 事务A开始查询余额100的用户得到10条 T2: 事务B开始插入一个余额150的新用户提交 T3: 事务A再次查询余额100的用户得到11条 ← 幻读注意不可重复读是针对已有记录的修改幻读是针对记录数量的变化。MySQL 的四种隔离级别MySQL 定义了四种隔离级别从低到高隔离级别脏读不可重复读幻读READ UNCOMMITTED读未提交❌ 会❌ 会❌ 会READ COMMITTED读已提交✅ 不会❌ 会❌ 会REPEATABLE READ可重复读✅ 不会✅ 不会❌ 会InnoDB 不会SERIALIZABLE串行化✅ 不会✅ 不会✅ 不会MySQL 默认隔离级别是 REPEATABLE READ可重复读而且 InnoDB 通过 Next-Key Lock 解决了幻读问题所以实际上 REPEATABLE READ 已经能防住所有问题了。实战看看每个隔离级别的表现咱们用实际 SQL 来验证一下假设你有个账户表CREATETABLEaccounts(idINTPRIMARYKEY,nameVARCHAR(50),balanceDECIMAL(10,2));INSERTINTOaccountsVALUES(1,小明,100.00);1. READ UNCOMMITTED读未提交-- 会话ASETSESSIONTRANSACTIONISOLATIONLEVELREADUNCOMMITTED;STARTTRANSACTION;SELECTbalanceFROMaccountsWHEREid1;-- 读到 100-- 会话B另一个终端STARTTRANSACTION;UPDATEaccountsSETbalance200WHEREid1;-- 注意这里没提交-- 会话ASELECTbalanceFROMaccountsWHEREid1;-- 读到 200脏读问题会话 A 读到了会话 B 未提交的数据。如果会话 B 回滚那会话 A 拿到的 200 就是无效的。2. READ COMMITTED读已提交-- 会话ASETSESSIONTRANSACTIONISOLATIONLEVELREADCOMMITTED;STARTTRANSACTION;SELECTbalanceFROMaccountsWHEREid1;-- 读到 100-- 会话BSTARTTRANSACTION;UPDATEaccountsSETbalance200WHEREid1;-- 没提交-- 会话ASELECTbalanceFROMaccountsWHEREid1;-- 还是读到 100防脏读-- 会话BCOMMIT;-- 会话ASELECTbalanceFROMaccountsWHEREid1;-- 读到 200不可重复读问题同一个事务内两次读取结果不一样不可重复读。Oracle 默认就是这个级别但 MySQL 默认不是。3. REPEATABLE READ可重复读MySQL 默认-- 会话ASETSESSIONTRANSACTIONISOLATIONLEVELREPEATABLEREAD;STARTTRANSACTION;SELECTbalanceFROMaccountsWHEREid1;-- 读到 100-- 会话BSTARTTRANSACTION;UPDATEaccountsSETbalance200WHEREid1;COMMIT;-- 会话ASELECTbalanceFROMaccountsWHEREid1;-- 还是读到 100可重复读牛逼之处同一个事务内多次读取同一行结果一致。MySQL 是怎么做到的MVCC多版本并发控制简单说就是每个事务开始时会生成一个快照Read View后面的查询都基于这个快照不受其他事务提交的影响。那如果会话 A 想更新呢-- 会话AUPDATEaccountsSETbalancebalance50WHEREid1;-- 这里会加行锁并且读取最新的值200所以结果是 250SELECTbalanceFROMaccountsWHEREid1;-- 读到 250注意UPDATE/DELETE/INSERT 操作会读取最新数据当前读不受快照影响。4. SERIALIZABLE串行化-- 会话ASETSESSIONTRANSACTIONISOLATIONLEVELSERIALIZABLE;STARTTRANSACTION;SELECT*FROMaccountsWHEREid1;-- 会话BSTARTTRANSACTION;INSERTINTOaccountsVALUES(2,小红,300);-- 阻塞等会话A提交才能执行原理SERIALIZABLE 会对所有读取加共享锁写操作加排他锁相当于事务排队执行性能最差但最安全。一般不用除非对数据一致性要求极高比如金融场景。InnoDB 怎么解决幻读的前面我说了InnoDB 的 REPEATABLE READ 能防幻读这是怎么做到的答案是Next-Key Lock临键锁。假设你的账户表有这些记录INSERTINTOaccountsVALUES(1,小明,100),(5,小红,200),(10,小刚,300);如果会话 A 执行-- 会话ASTARTTRANSACTION;SELECT*FROMaccountsWHEREid5FORUPDATE;-- 命中了 id10 这条记录InnoDB 不会只锁id10这一行而是锁住(5, 10]这个区间Next-Key Lock 记录锁 间隙锁。那会话 B 想插入id7的记录-- 会话BINSERTINTOaccountsVALUES(7,小华,150);-- 阻塞因为 (5, 10] 被锁住了结果会话 B 必须等会话 A 提交后才能插入幻读就不可能发生了。如何查看和设置隔离级别查看当前隔离级别-- MySQL 8.0SELECTtransaction_isolation;-- 或者SHOWVARIABLESLIKEtransaction_isolation;-- MySQL 5.7 及之前SELECTtx_isolation;设置隔离级别-- 设置当前会话的隔离级别只对当前连接有效SETSESSIONTRANSACTIONISOLATIONLEVELREADCOMMITTED;-- 设置全局隔离级别对新连接有效当前连接不变SETGLOBALTRANSACTIONISOLATIONLEVELREADCOMMITTED;-- 修改配置文件永久生效-- 在 my.cnf 或 my.ini 里加[mysqld]transaction-isolationREAD-COMMITTED实战建议1. 别随便改隔离级别MySQL 默认 REPEATABLE READ 是经过大量实践验证的能解决绝大多数问题。除非你有明确理由否则别改。我们公司就有人把隔离级别改成 READ COMMITTED结果出了不可重复读的 bug排查了一整天。2. 长事务是性能杀手隔离级别越高事务之间的隔离性越好但并发性能越差。如果你开了个长事务比如跑了 10 分钟还没提交会阻塞很多其他操作。-- 查看当前运行的事务SELECT*FROMinformation_schema.innodb_trx;建议事务要尽量短小用完马上提交。3. 慎用 SELECT … FOR UPDATESELECT ... FOR UPDATE会加排他锁容易引发死锁。-- 会话ASTARTTRANSACTION;SELECT*FROMaccountsWHEREid1FORUPDATE;-- 会话BSTARTTRANSACTION;SELECT*FROMaccountsWHEREid2FORUPDATE;UPDATEaccountsSETbalance100WHEREid1;-- 阻塞-- 会话AUPDATEaccountsSETbalance200WHEREid2;-- 死锁建议只在必要时用FOR UPDATE并且尽量按固定顺序加锁比如按 id 排序。总结事务隔离级别从低到高READ UNCOMMITTED → READ COMMITTED → REPEATABLE READ → SERIALIZABLE隔离级别越低并发性能越好但数据一致性越差MySQL 默认 REPEATABLE READ通过 MVCC 防不可重复读通过 Next-Key Lock 防幻读别随便改隔离级别慎用长事务和SELECT ... FOR UPDATE如果你能把 MVCC 和 Next-Key Lock 讲清楚面试官绝对眼前一亮。实战代码都在我本地跑过你可以放心复制。如果有问题欢迎评论区交流
http://www.zskr.cn/news/1355195.html

相关文章:

  • 3步搞定日语Galgame翻译的终极方案:TsubakiTranslator完全指南
  • 如何高效实现STL到STEP格式转换:stltostp工具终极指南
  • 2026南京财税合规避坑指南:中小企业如何选对财务外包与股权架构伙伴 - 小艾信息发布
  • 泉盛UV-K5/K6固件完全升级指南:从基础通信到专业监测的终极改造
  • 2026年5月值得信赖的东莞热熔机厂家怎么选厂家推荐榜,伺服超声波热熔机、热板式熔接机、旋熔机厂家选择指南 - 海棠依旧大
  • Source Sans 3:解决现代Web字体性能与设计矛盾的工程化方案
  • 5分钟快速上手:TegraRcmGUI Switch注入图形化工具终极指南
  • RK3568播放RTSP摄像头实测:软解1080P直接CPU跑满,降到360P才流畅,硬解到底怎么搞?
  • 2026年乌鲁木齐黄金回收权威测评:六大机构实地对比,谁更靠谱? - 上门黄金回收
  • 广州全屋整装深度评测:四大头部装企的资质与服务对决 - 互联网科技品牌测评
  • Bebas Neue 开源字体深度解析:几何美学的技术实现与实战应用
  • 告别串口调试烦恼:用MAX3221EUE+芯片搞定TTL转RS232的完整电路与PCB布局指南
  • 金融MBA择校怎么选?中欧金融MBA 高含金量项目深度解读 - 博客万
  • 微信立减金闲置不用?2026年轻松回收的实用方法 - 京顺回收
  • 2026年新疆HDPE管道与市政给排水工程供应商选型指南 - 精选优质企业推荐官
  • SAM-BA烧录翻车实录:避开AT91SAM9系列SPI Flash初始化的3个坑
  • 2026年5月热门的家电维修平台加盟机构排行厂家推荐榜,速婆生活/鲁班到家/神州联保/苏宁帮客/京东服务+厂家选择指南 - 海棠依旧大
  • 2026年5月专业的重庆职称办理机构哪家强厂家推荐榜,建筑、机电、市政、水利、土建等专业职称申报厂家选择指南 - 海棠依旧大
  • 上海鸿沄高空作业:上海外墙防火涂料施工公司 - LYL仔仔
  • UE5 Paper2D BitmapUtils.h 深度解析:位图预处理核心机制
  • 市面高耐磨地板怎么选靠谱厂家?无忧家居专业实力一目了然,红芯火盾地板/黑金刚防水地板,耐磨地板生产企业哪家可靠 - 品牌推荐师
  • 春节回家抢机票哪个平台好?美团机票省心划算有保障 - 博客万
  • 2026年新疆HDPE管道与市政给排水工程供应商深度横评指南 - 精选优质企业推荐官
  • 如何在5分钟内掌握Maya到Web 3D的终极转换工具:完整glTF插件指南
  • 革命性智能游戏助手:基于视觉识别的鸣潮自动化创新方案
  • 亲子跨省买机票哪个平台可提前选座?美团机票省心之选 - 博客万
  • 2026年上海寻衅滋事罪辩护律师如何选?找案例多、专业的律师! - 法律资讯
  • 手把手教你用STM32F767驱动RGB屏幕:从CubeMX配置LTDC到LVGL移植避坑指南
  • 重庆黄金回收实地测评:五家靠谱门店真实行情 - 李宏哲1
  • 深度解析:专业高效的Godot逆向工程工具全攻略