【MySQL 零基础入门】事务精讲(二):ACID 特性与并发问题

是思成呀:个人主页

个人专栏《C++知识总结》《MySQL 零基础入门到实战》


引言

事务之所以能保证数据一致性,核心是靠 ACID 四大特性 "保驾护航"------ 原子性保证操作不可分割,一致性保证数据逻辑无误,隔离性保证多事务互不干扰,持久性保证数据永久保存。而在多事务并发执行时,即使有 ACID,也可能出现脏读、不可重复读、幻读等问题(比如同时给两名高中生缴费导致余额计算错误、查询学生成绩时读到未提交的临时数据)。本文带你吃透 ACID 的底层逻辑,理清并发事务的三大问题,为后续学习隔离级别打下基础!

目录

一、事务的四大特性(ACID)(精简案例解读)

[1. 原子性(Atomicity)](#1. 原子性(Atomicity))

[2. 一致性(Consistency)](#2. 一致性(Consistency))

[3. 隔离性(Isolation)](#3. 隔离性(Isolation))

[4. 持久性(Durability)](#4. 持久性(Durability))

二、并发事务引发的三大问题

[1. 脏读(Dirty Read)](#1. 脏读(Dirty Read))

[2. 不可重复读(Non-Repeatable Read)](#2. 不可重复读(Non-Repeatable Read))

[3. 幻读(Phantom Read)](#3. 幻读(Phantom Read))

三、问题根源与解决思路

结尾


一、事务的四大特性(ACID)(精简案例解读)

ACID 是事务的核心属性,保证了事务的可靠性和数据一致性,精简后 5 名学生的场景更易理解:

1. 原子性(Atomicity)

  • 定义:事务是不可分割的最小操作单元,要么全部执行成功,要么全部失败回滚。
  • 案例:高中生缴费事务中,"扣减林墨涵账户余额" 和 "更新缴费状态" 必须同时成功或同时失败,不会出现中间状态(如余额扣了但状态没更)。
  • 实现原理:MySQL 通过日志(undo log)记录事务的修改操作,回滚时通过日志撤销已执行的操作。

2. 一致性(Consistency)

  • 定义:事务执行前后,数据库的完整性约束(如主键唯一、余额非负)保持不变,数据逻辑一致。
  • 案例:林墨涵缴费前账户余额 2000 元 + 缴费记录状态 "未缴费",缴费后余额 500 元 + 状态 "已缴费",整体数据逻辑无矛盾;若出现余额扣了但状态仍为 "未缴费",则违反一致性。
  • 关键要求:事务必须满足业务规则(如学生余额不能为负),否则即使原子性满足,一致性也会被破坏。

3. 隔离性(Isolation)

  • 定义:多个事务并发执行时,事务之间相互隔离,每个事务感觉不到其他事务的存在。
  • 案例:事务 A 给林墨涵缴费(未提交),事务 B 查询林墨涵余额时,不会看到事务 A 未提交的临时数据(余额仍为 2000 元)。
  • 实现原理:通过锁机制和多版本并发控制(MVCC)实现,避免并发事务相互干扰。

4. 持久性(Durability)

  • 定义:事务一旦提交,对数据的修改会永久保存到数据库(即使服务器崩溃,数据也不会丢失)。
  • 实现原理:MySQL 通过 redo log 记录已提交的修改,崩溃恢复时通过 redo log 重新应用修改,保证数据持久化。
  • 验证方式:事务提交后,数据会写入磁盘的.ibd 文件(InnoDB 数据文件),重启数据库后林墨涵的余额和缴费状态依然是修改后的值。

二、并发事务引发的三大问题

当多个事务同时操作 5 名高中生数据时,若没有合适的隔离机制,会引发以下核心问题:

1. 脏读(Dirty Read)

  • 定义:一个事务读取到另一个事务未提交的数据(临时数据,可能被回滚)。
  • 场景演示
  1. 事务 A 开启,执行 UPDATE student_account SET balance = 500 WHERE student_name = '林墨涵'(未提交);
  2. 事务 B 查询林墨涵的余额,得到 500 元(脏数据);
  3. 事务 A 执行 ROLLBACK,林墨涵余额恢复为 2000 元;
  4. 事务 B 读取的 500 元是无效数据,若基于此判断林墨涵余额不足拒绝缴费,就会导致业务错误。
  • 危害:基于脏数据的决策会导致业务逻辑错误(如误判高中生缴费能力)。

2. 不可重复读(Non-Repeatable Read)

  • 定义:同一事务内多次读取同一数据,结果不一致(其他事务提交了更新操作)。
  • 场景演示(精简版)
  1. 事务 A 开启,首次查询林墨涵余额为 2000 元;
  2. 事务 B 执行 UPDATE student_account SET balance = 500 WHERE student_name = '林墨涵' 并提交;
  3. 事务 A 再次查询林墨涵余额,得到 500 元,与首次结果不一致。
  • 与脏读的区别:不可重复读读取的是已提交的数据,脏读读取的是未提交数据。

3. 幻读(Phantom Read)

  • 定义:同一事务内多次执行相同的范围查询,结果集的行数不一致(其他事务提交了插入 / 删除操作)。
  • 场景演示(精简版)
  1. 事务 A 开启,查询余额 > 2000 的高中生,得到苏语桐、楚泽宇、温知夏 3 人;
  2. 事务 B 插入一条新记录:INSERT INTO student_account(student_name, balance, class_name) VALUES ('江弈辰', 2200, '高一(1)班') 并提交;
  3. 事务 A 再次执行相同查询,得到 4 人,行数增加("幻影" 行出现)。
  • 与不可重复读的区别:不可重复读针对已有数据的修改(如林墨涵余额变化),幻读针对新数据的插入 / 删除(如新增江弈辰的记录)。

三、问题根源与解决思路

并发事务问题的本质是:多个事务同时操作同一高中生数据,且未对数据访问顺序进行有效控制。解决思路:通过设置事务隔离级别,在 "数据一致性" 和 "并发性能" 之间做权衡 ------ 隔离级别越高,数据越安全,但并发性能越低(比如同时缴费的高中生数量会减少)。

结尾

🍍 我是思成!若这篇内容帮你理清了 MySQL 事务 ACID 特性与并发问题的核心逻辑:

👀 【关注】跟我一起拆解 MySQL 核心知识点,从 ACID 特性到隔离级别,吃透每一个事务并发规则

❤️ 【点赞】让技术干货被更多人看见,让抽象的脏读、幻读逻辑变得易懂

⭐ 【收藏】把 ACID 四大特性、高中生数据并发问题案例存好,事务开发 / 面试时随时查阅

💬 【评论】分享你遇到的高中生数据事务并发问题,或想深挖的事务知识点,一起交流进步

🗳️ 【投票】告诉我你最想拆解的下一个知识点(比如事务隔离级别?锁机制?)

技术学习没有捷径,但找对思路能少走弯路~愿我们都能把抽象的事务特性,转化为可落地的并发控制方案,一步步构建健壮的数据库事务体系!

相关推荐
晓梦林2 小时前
BUUCTF findKey-学习笔记
笔记·学习
0566462 小时前
agent学习Day15——SQLAlchemy 查询过滤、分页与历史列表接口
python·学习·fastapi
敲个大西瓜3 小时前
Redis一百道核心面试题
数据库·redis·缓存
炎武丶航4 小时前
汽车功能测试学习(1):FCW前方碰撞预警
功能测试·学习·汽车
x17388062734 小时前
XXE外部实体注入
xml·笔记
無a伟6 小时前
Redis持久化详解:RDB与AOF原理、配置、优缺点
数据库
小罗水7 小时前
附录A 各微服务完整 application.yml 配置汇总
数据库·elasticsearch·微服务
muddjsv7 小时前
SQLite 外键进阶:CASCADE / SET NULL / 级联更新与完整性校验
数据库·sqlite
APItesterCris7 小时前
Open Claw 实战教程:5 分钟搭建京东商品自动化监控与数据分析系统
大数据·运维·数据库·数据仓库·自动化
Nturmoils8 小时前
查库存的 SQL 时灵时不灵,最后发现是 WHERE 里两个函数在打架
数据库