Python全栈入门到实战【数据库篇 18】MySQL事务隔离级别详解,并发数据安全的核心控制

📅 2026/8/1 6:26:14 👁️ 阅读次数 📝 编程学习
Python全栈入门到实战【数据库篇 18】MySQL事务隔离级别详解,并发数据安全的核心控制

前言

上一篇《数据库篇 17》中,我们已经掌握了事务的基本操作和ACID四大核心特性,学会了如何通过事务保证数据的原子性和一致性。本篇作为数据库篇的第十八篇,我们将深入讲解事务ACID中的隔离性,这是并发数据安全的核心。当多个事务同时操作同一批数据时,如果没有适当的隔离机制,就会出现脏读、不可重复读、幻读等严重的数据不一致问题。我们将详细讲解这三个并发问题,以及MySQL提供的四种事务隔离级别,教你如何根据业务需求选择合适的隔离级别。

本文为Python全栈开发者与数据库入门者量身打造,通过"问题定义+场景示例+实战验证"的方式,清晰讲解每一个并发问题的产生原因和解决方法,每一个隔离级别都有可直接运行的验证代码,同时重点标注生产环境中的最佳实践和常见陷阱,即使是完全没有并发编程经验的同学,也能快速掌握事务隔离级别的核心知识。

本节核心学习内容:

  1. 并发事务问题:脏读、不可重复读、幻读的定义与场景
  2. 事务隔离级别:四种隔离级别的对比与解决能力
  3. 隔离级别操作:查看与设置会话/全局隔离级别的语法
  4. 完整实战:逐级别验证并发问题的存在与解决
  5. 常见误区:全局与会话隔离、幻读的本质等避坑指南
  6. 最佳实践:生产环境隔离级别的选择原则
  7. 核心总结:并发问题与隔离级别速查表

文章目录

  • 前言
  • 一、并发事务带来的三个问题
    • 1.1 脏读
    • 1.2 不可重复读
    • 1.3 幻读
  • 二、MySQL的四种事务隔离级别
    • 2.1 隔离级别解决能力对比
    • 2.2 查看与设置隔离级别
      • 查看当前隔离级别
      • 设置隔离级别
  • 三、实战演示:不同隔离级别的效果验证
    • 3.1 准备测试数据
    • 3.2 验证读未提交(Read uncommitted)
    • 3.3 验证读已提交(Read committed)
    • 3.4 验证可重复读(Repeatable Read)
    • 3.5 验证串行化(Serializable)
  • 四、常见误区与最佳实践
  • 五、核心总结:事务并发问题与隔离级别速查表
    • 并发问题总结
    • 隔离级别总结
    • 常用操作语法
  • 六、专栏订阅

一、并发事务带来的三个问题

当多个事务同时访问数据库中的同一批数据时,如果数据库没有提供隔离机制,就会出现以下三个经典的并发问题,导致数据不一致:

问题描述
脏读一个事务读到了另外一个事务还没有提交的数据
不可重复读一个事务先后读取同一条记录,但两次读取的数据不同
幻读一个事务按照条件查询数据时,没有对应的行;但插入数据时,又发现该行已经存在,好像出现了"幻影"

1.1 脏读

定义:一个事务读到了另一个事务未提交的修改数据。

场景示例

  1. 事务A读取张三的账户余额为2000元
  2. 事务B修改张三的账户余额为1000元,但尚未提交事务
  3. 事务A再次读取张三的账户余额,得到1000元(读到了事务B未提交的数据)
  4. 事务B回滚,张三的账户余额恢复为2000元
  5. 此时事务A读到的1000元就是"脏数据",基于此数据的所有操作都是错误的

1.2 不可重复读

定义:在同一个事务内,先后两次读取同一条记录,得到的结果不同。

场景示例

  1. 事务A读取张三的账户余额为2000元
  2. 事务B修改张三的账户余额为1000元,并提交事务
  3. 事务A再次读取张三的账户余额,得到1000元
  4. 在同一个事务A中,两次读取同一条记录的结果不同,这就是不可重复读

1.3 幻读

定义:一个事务按照条件查询数据时,没有找到对应的行;但当它尝试插入该行数据时,又发现该行已经存在,好像出现了"幻影"。

场景示例

  1. 事务A查询id=1的用户,结果为空
  2. 事务B插入id=1的用户,并提交事务
  3. 事务A尝试插入id=1的用户,报错"主键冲突"
  4. 事务A再次查询id=1的用户,结果仍然为空(在可重复读隔离级别下)
  5. 对于事务A来说,id=1的用户就像"幻影"一样,看不见但又插不进去

二、MySQL的四种事务隔离级别

为了解决上述并发问题,MySQL提供了四种事务隔离级别,隔离级别从低到高依次为:

  1. Read uncommitted(读未提交)
  2. Read committed(读已提交)
  3. Repeatable Read(可重复读):MySQL的默认隔离级别
  4. Serializable(串行化)

2.1 隔离级别解决能力对比

不同的隔离级别可以解决不同的并发问题,隔离级别越高,数据越安全,但性能越低。

隔离级别脏读不可重复读幻读
Read uncommitted
Read committed
Repeatable Read(默认)
Serializable

✅ 表示存在该问题,❌ 表示解决了该问题

2.2 查看与设置隔离级别

查看当前隔离级别

-- MySQL 8.0及以上版本SELECT@@TRANSACTION_ISOLATION;-- MySQL 5.x版本SELECT@@tx_isolation;

设置隔离级别

-- 设置当前会话的隔离级别(只对当前连接有效)SETSESSIONTRANSACTIONISOLATIONLEVEL{READUNCOMMITTED|READCOMMITTED|REPEATABLEREAD|SERIALIZABLE};-- 设置全局的隔离级别(对所有新连接有效,已存在的连接无效)SETGLOBALTRANSACTIONISOLATIONLEVEL{READUNCOMMITTED|READCOMMITTED|REPEATABLEREAD|SERIALIZABLE};

⚠️ 重要注意:不要随便修改全局隔离级别,这会影响所有连接到数据库的应用。如果需要修改,应该只修改当前会话的隔离级别。

三、实战演示:不同隔离级别的效果验证

下面我们通过两个MySQL客户端窗口,分别模拟两个并发事务,验证不同隔离级别下的并发问题。

3.1 准备测试数据

-- 创建账户表CREATETABLEaccount(idINTPRIMARYKEYAUTO_INCREMENT,nameVARCHAR(20)NOTNULL,moneyDECIMAL(10,2)NOTNULLDEFAULT0);-- 插入测试数据INSERTINTOaccount(name,money)VALUES('张三',2000.00),('李四',2000.00);

3.2 验证读未提交(Read uncommitted)

目标:验证脏读问题

步骤客户端A(事务A)客户端B(事务B)
1SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
2BEGIN;BEGIN;
3SELECT * FROM account WHERE name = '张三';
结果:张三 2000.00
4UPDATE account SET money = 1000 WHERE name = '张三';
5SELECT * FROM account WHERE name = '张三';
结果:张三 1000.00
(读到了事务B未提交的数据,脏读发生)
6ROLLBACK;
7SELECT * FROM account WHERE name = '张三';
结果:张三 2000.00

3.3 验证读已提交(Read committed)

目标:验证脏读已解决,但不可重复读仍然存在

步骤客户端A(事务A)客户端B(事务B)
1SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
2BEGIN;BEGIN;
3SELECT * FROM account WHERE name = '张三';
结果:张三 2000.00
4UPDATE account SET money = 1000 WHERE name = '张三';
5SELECT * FROM account WHERE name = '张三';
结果:张三 2000.00
(没有读到未提交的数据,脏读已解决)
6COMMIT;
7SELECT * FROM account WHERE name = '张三';
结果:张三 1000.00
(同一个事务内两次读取结果不同,不可重复读发生)

3.4 验证可重复读(Repeatable Read)

目标:验证脏读和不可重复读已解决,但幻读仍然存在

步骤客户端A(事务A)客户端B(事务B)
1SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
2BEGIN;BEGIN;
3SELECT * FROM account WHERE id = 3;
结果:空
4INSERT INTO account(id, name, money) VALUES (3, '王五', 3000.00);
5COMMIT;
6SELECT * FROM account WHERE id = 3;
结果:空
(可重复读保证了同一个事务内读取结果一致)
7INSERT INTO account(id, name, money) VALUES (3, '王五', 3000.00);
报错:Duplicate entry ‘3’ for key ‘PRIMARY’
(插入失败,幻读发生)
8SELECT * FROM account WHERE id = 3;
结果:仍然为空

3.5 验证串行化(Serializable)

目标:验证所有并发问题都已解决

步骤客户端A(事务A)客户端B(事务B)
1SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
2BEGIN;BEGIN;
3SELECT * FROM account WHERE id = 4;
结果:空
4INSERT INTO account(id, name, money) VALUES (4, '赵六', 4000.00);
(阻塞,等待事务A结束)
5COMMIT;阻塞解除,插入成功
6SELECT * FROM account WHERE id = 4;
结果:赵六 4000.00
(没有幻读问题)

四、常见误区与最佳实践

  1. 全局与会话隔离级别的区别SESSION级别只对当前连接有效,GLOBAL级别对所有新连接有效,已存在的连接不受影响。生产环境中永远不要修改全局隔离级别。
  2. 默认隔离级别的选择:MySQL默认的Repeatable Read隔离级别已经解决了脏读和不可重复读问题,能够满足绝大多数业务场景的需求,不需要修改。
  3. 串行化的性能问题Serializable隔离级别会将所有事务串行执行,性能极差,只有在对数据一致性要求极高的场景(如金融交易)才会使用。
  4. 幻读的本质:幻读不是"读不到",而是"插入失败"。MySQL的可重复读隔离级别通过间隙锁(Gap Lock)在很大程度上解决了幻读问题,但不能完全解决。
  5. 隔离级别与性能的权衡:隔离级别越高,数据越安全,但并发性能越低。应该根据业务对数据一致性的要求,选择最低的能够满足需求的隔离级别。

五、核心总结:事务并发问题与隔离级别速查表

为了方便后续开发时快速查阅,整理了并发问题与隔离级别的核心速查表:

并发问题总结

问题定义本质
脏读读到未提交的数据读取了临时数据
不可重复读同一事务内两次读取同一条记录结果不同数据被修改
幻读查询不到但插入失败数据被插入

隔离级别总结

隔离级别解决的问题存在的问题性能适用场景
Read uncommitted脏读、不可重复读、幻读最高几乎不使用
Read committed脏读不可重复读、幻读Oracle、PostgreSQL默认
Repeatable Read(默认)脏读、不可重复读幻读MySQL默认,绝大多数业务场景
Serializable所有问题最低对数据一致性要求极高的场景

常用操作语法

操作语法
查看当前隔离级别SELECT @@TRANSACTION_ISOLATION;
设置会话隔离级别SET SESSION TRANSACTION ISOLATION LEVEL 级别;
设置全局隔离级别SET GLOBAL TRANSACTION ISOLATION LEVEL 级别;

六、专栏订阅

  • 专栏优点?《Python从入门到实战》,专栏内容涵盖:Python基础到高级编程、并发编程(进程/线程/协程)、网络编程(TCP/UDP/Socket)、核心内置/第三方模块、数据库核心实战、Web开发(Django/Flask/FastAPI框架)、数据库(MySQL/ORM/异步数据库)、网络爬虫(同步/异步/分布式)、AI实战、Linux部署运维等全栈核心知识,以项目驱动教学,构建清晰学习路径,适合零基础入门和进阶提升的同学,跟着一步步从入门到精通!专栏地址:https://blog.csdn.net/zsh_1314520/category_13108073.html
  • 文章是永久吗?一次订阅后可永久免费查看专栏内所有文章,后续会持续更新全栈相关内容,第一时间获取最新教程!
  • 有答疑交流群吗?订阅专栏后有专属的全栈学习答疑群,群内提供专业问题答疑、和众多学习者抱团取暖,一起沉淀技术、赋能成长!
  • 进群方式?订阅专栏后可直接在专栏内申请加入答疑群,或私信博主沟通进群事宜:https://bbs.csdn.net/topics/620104702
  • 更多干货?点赞+收藏+关注博主不迷路!博主博客链接:https://blog.csdn.net/zsh_1314520?spm=1000.2115.3001.5343,专注Python全栈技术分享,评论区留言问题会一一回复,助力大家轻松搞定Python全栈!

【原创声明】
除本文原文地址以外,如发现同款内容皆为盗版,本文已收录于《Python全栈:从入门到实战》,请勿购买盗版文章和专栏,如购买盗版内容不提供任何服务。原文地址:https://blog.csdn.net/zsh_1314520/article/details/163373625