【MySQL百日打怪升级第17天】事务基础:ACID 特性——面试必问的第一题

简介: 本系列第17天详解MySQL事务ACID特性:原子性靠Undo Log实现回滚与MVCC快照读;一致性需数据库约束+业务逻辑协同保障;隔离性依赖锁和MVCC;持久性通过Redo Log的WAL机制确保。附真实避坑指南与面试高频考点。

【第17天】每天一个MySQL知识点,百日打怪升级

事务基础:ACID 特性——面试必问的第一题


大家好,我是一名拥有10年以上经验的DBA老兵,没有那多。

做这个系列,源于一个朴素的愿望:把踩过的坑、总结的经验系统化输出,希望能帮到刚入行或想进阶的兄弟们。

让我们开始今天的第17天内容。


背景引入

💡 两个人同时抢最后一个座位——数据库是怎么保证不卖超的?

说个场景。

你打开 App 买一张高铁票,从北京到上海,G1 次,只剩最后一张。你点下单的同时,另一个人也在点。

系统先查了一下:余票 1 张。然后扣库存。

但如果你们俩的查询和扣减操作没有"保护"起来,就可能出现——两个人都查到余票 1 张,都成功扣了库存,结果变成 -1 张。后台一对账,发现卖超了。

这就是没有事务的后果。

事务就是给一组操作加上一个"要么全做,要么全不做"的边界。MySQL 里写 BEGINCOMMIT,就是告诉数据库:这中间的所有操作,必须当成一个整体来处理。

今天的目标:搞懂事务的四个核心特性 ACID,以及 InnoDB 是怎么实现它们的。


核心概念

什么是事务?

事务就是一个不可分割的工作单元。你把它理解为数据库里的"原子操作"——里面的步骤要么全部成功,要么全部回滚,不存在"做了一半"的状态。

BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;
COMMIT;

转账 100 块,A 扣钱和 B 加钱必须同时成功。如果 A 扣完了,B 加钱之前数据库崩了——钱就丢了。事务就是来杜绝这种事的。


ACID 拆开讲

A——Atomicity(原子性)

要么全做,要么全不做。

InnoDB 靠 Undo Log 来实现。事务内的每一条写操作,都会同时记一条"怎么改回来"的日志在 Undo Log 里(存在系统表空间或独立的 Undo 表空间中,本身也是持久化的)。如果事务要回滚,InnoDB 就按 Undo Log 倒着重放,把数据恢复到事务开始前的样子。

面试常问的一个点:Undo Log 不只是用来回滚的,它还服务于 MVCC 的快照读(明天会细讲)。一条日志,两个用途。


C——Consistency(一致性)

事务执行前后,数据必须满足所有约束和业务规则。

扣了 A 的钱,B 必须多同样多的钱。余额不能为负。库存不能为负。

一致性其实是 ACID 里最"不易察觉"的一个。它不完全靠数据库——约束(主键、唯一键、外键、CHECK)是数据库保证的,但业务规则(比如"余额不小于 0")通常靠应用代码来实现。

MySQL 的一个常见"不一致"场景:用 UPDATE ... SET balance = balance - 100,如果 balance 是负数但没加 CHECK 约束,数据库不会拦你。一致性是业务和数据库共同的责任。


I——Isolation(隔离性)

多个事务同时执行,彼此不能干扰。

这个昨天已经讲了不少了——锁、隔离级别、MVCC,都是为隔离性服务的。隔离性越强,数据越安全,但并发越低。

MySQL 的默认隔离级别 REPEATABLE READ(RR)隔离性相当强,代价就是前面的 Gap Lock。如果你关注性能多于绝对一致性,READ COMMITTED(RC)通常是更好的选择。很多互联网公司默认就用 RC,配合 ROW 格式 binlog。


D——Durability(持久性)

事务提交后,数据必须永久保存,即使系统崩溃也不丢。

InnoDB 靠 Redo Log 来实现。它的做法是 WAL(Write-Ahead Logging):先写日志,再写数据。

事务提交时,不是直接把数据页写回磁盘(那太慢了),而是把修改记录写到 Redo Log,然后告诉客户端"事务成功了"。

Redo Log 是顺序写,磁盘性能很好。万一断电重启,InnoDB 的崩溃恢复分两步:

  1. REDO 阶段——扫 Redo Log,重放所有已提交但还没刷到数据页的修改,保证持久性
  2. UNDO 阶段——扫 Undo Log,回滚所有崩溃前没提交的事务,保证原子性

两步走完,数据库才回到一致状态。

这里有一个关键参数组合:

参数组合 安全性 性能
sync_binlog=1 + innodb_flush_log_at_trx_commit=1 最高(但最慢) 每次提交都 fsync
sync_binlog=0 + innodb_flush_log_at_trx_commit=2 最多可能丢最近 1 秒内提交的事务 性能好很多

所谓的"双一"配置(两个参数都是 1)就是 DBA 最看重的数据安全红线。丢了数据,谁都赔不起。


实战案例

场景一:理解原子性的"反例"

-- 没有事务的转账
UPDATE account SET balance = balance - 100 WHERE id = 1;
-- 此时 MySQL 崩了... 钱扣了但没加上
UPDATE account SET balance = balance + 100 WHERE id = 2;

有事务保护:

BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;
COMMIT;
-- 要么两个都成功,要么一个都不执行

实际开发中常见的问题是:代码里写了事务,但在 catch 块里忘了 ROLLBACK。事务会继续挂着,锁不释放,其他请求只能干等。如果连接池满了,整个服务就挂了。


场景二:隔离性不足时的并发问题

有次排查一个"库存显示为 0 但还能下单"的 bug,根因很简单——用的是 READ UNCOMMITTED 隔离级别。A 事务下单扣库存还没提交,B 事务读到了 A 未提交的库存(脏读),此时 A 回滚了,B 拿着一个"假"库存继续下单。

隔离级别不足的表现就是:你读到的数据可能是不存在的。


避坑指南

⚠️ 真实踩过的坑:

  1. 没 rollback 的事务最坑

    • 业务逻辑异常了,catch 里只记日志没 rollback
    • 事务一直挂着,连接不释放,最终连接池撑爆
    • 代码里写事务时,finallycatch 里一定要有 rollback
    • 工程化建议:用 Spring 等框架时,优先依赖声明式事务(@Transactional),它自动处理回滚,比手动 commit/rollback 安全得多
  2. "双一"配置不能随便改

    • sync_binlog=0innodb_flush_log_at_trx_commit != 1 在非核心业务上可以接受
    • 但金融、订单等核心业务必须"双一"——丢了数据是要背责任的
  3. 一致性不是数据库一个人的事

    • 数据库保证的是约束级别的一致性
    • 业务规则的一致性(余额不为负、库存不超卖)需要应用代码配合
    • 可以在数据库加 CHECK 约束兜底:ALTER TABLE account ADD CHECK (balance >= 0)
    • ⚠️ 注意:MySQL 8.0.16 之前虽然支持 CHECK 语法,但不会实际检查——加了等于没加。从 8.0.16 开始才真正强制检查。如果你还在用 5.7,一致性全靠应用自己保证
  4. 事务不要开太大

    • 前面两天的文章说过,大事务导致锁范围大、binlog 大、复制延迟
    • 一条事务里只放必要的操作,无关的查询和更新不要塞进去

思考题

🤔 互动时间:

  1. 假设一张表没有设置主键,InnoDB 的 Redo Log 还能保证持久性吗?
    提示:想想没有主键时 InnoDB 用什么来定位行,Redo Log 记录的是数据页偏移量还是逻辑 SQL?

  2. COMMIT 执行完但客户端没收到响应——这时候如果断电重启,数据到底在不在?
    提示:COMMIT 的核心是刷 Redo Log,刷成功了数据就在,没刷成功就不在。关键在于 COMMIT 语句返回前 Redo Log 落盘了没有。

  3. 为什么说「Undo Log 既服务于原子性,也服务于隔离性」?它跟 MVCC 是什么关系?
    提示:MVCC 的快照读需要能回溯到事务开始前的数据版本——这些旧版本就存在 Undo Log 里。原子性用 Undo Log 回滚,隔离性用 Undo Log 构建历史版本链。


总结

🎯 面试考点

  • 事务的 ACID:原子性靠 Undo Log一致性靠约束+业务隔离性靠锁+MVCC持久性靠 Redo Log
  • Undo Log 双重身份:原子性(回滚)+ MVCC(快照读)
  • Redo Log 是 WAL(Write-Ahead Logging):先写日志,再写数据,崩溃后重放
  • "双一"配置(sync_binlog=1 + innodb_flush_log_at_trx_commit=1)是数据安全红线
  • 事务不是越大越好——大事务 = 大锁 + 大 binlog + 大延迟

今天就试一下:连上你的数据库,跑一下这两条命令,看看当前是什么值:

SHOW VARIABLES LIKE 'sync_binlog';
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';

如果是双 1——你的数据很安全。如果不是——想一想,如果现在断电,你会丢多少数据?


下期预告:事务隔离级别详解 —— 面试必问!

全本合集《每天一个MySQL知识点,百日打怪升级》


有问题欢迎评论区交流,明天见!

相关文章
|
1月前
|
SQL 算法 关系型数据库
【MySQL百日打怪升级第10天】JOIN的底层原理与优化:NLJ、Hash Join 与 Merge Join
本文系统解析MySQL三大JOIN算法:NLJ(含Simple/Index/Block变体)、8.0.18引入的Hash Join(O(N+M)复杂度,专治无索引大表连接),以及面试常考但MySQL原生不支持的Sort-Merge Join,附实战EXPLAIN识别与优化指南。(239字)
192 5
|
4月前
|
人工智能 API 机器人
OpenClaw 用户部署和使用指南汇总
本文档为OpenClaw(原MoltBot)官方使用指南,涵盖一键部署(阿里云轻量服务器年仅68元)、钉钉/飞书/企微等多平台AI员工搭建、典型场景实践及高频问题FAQ。同步更新产品化修复进展,助力用户高效落地7×24小时主动执行AI助手。
29770 253
|
关系型数据库 MySQL 数据库
Mysql数据库redo log及binlog的写入
Mysql数据库redo log及binlog的写入
|
人工智能 运维 关系型数据库
智能运维+多模型服务能力,阿里云 RDS AI 助手旗舰版正式上线!
RDS AI 助手旗舰版在 RDS AI 助手专业版智能运维能力的基础上,提供灵活模型选择、智能模型路由、多模型灾备、API Key 集成等更自主可控、灵活便捷的模型服务,并支持纳管运维各类环境部署的数据库。
智能运维+多模型服务能力,阿里云 RDS AI 助手旗舰版正式上线!
|
6天前
|
安全 Java C++
【Java基础】集合框架: ConcurrentHashMap核心原理:JDK1.7 vs 1.8+ 区别、线程安全实现、分段锁 vs CAS+synchronized、扩容机制
ConcurrentHashMap是Java高并发场景下线程安全的哈希表实现,JDK1.7采用Segment分段锁(16段独立加锁),JDK1.8升级为CAS+synchronized细粒度桶锁,并引入红黑树与多线程协助扩容,显著提升性能与扩展性。
|
6天前
|
SQL 关系型数据库 MySQL
【第一阶段总结】MySQL基础20天 —— 知识地图与避坑复盘
本文是MySQL基础20天学习的系统复盘,涵盖架构、索引、SQL优化、事务、锁五大模块,提炼核心知识地图与高频避坑点(如无索引导致全表锁、RR下快照读与当前读差异等),并附面试考点与自测清单,助力夯实底层原理,平稳进阶。(239字)
93 1
|
6天前
|
存储 安全 Java
【Java基础】集合框架: HashMap核心原理:JDK1.7 vs 1.8+ 区别、数据结构、哈希函数、扩容机制、put/get全流程、红黑树转换阈值(附《思维导图》+《面试高频考点清单》)
本文系统对比JDK1.7与1.8+中HashMap的底层原理,涵盖数据结构(数组+链表→+红黑树)、哈希函数、扩容机制、插入方式及并发问题等核心差异,助你深入理解性能优化逻辑与面试高频考点。
|
1月前
|
SQL 关系型数据库 MySQL
【MySQL百日打怪升级第14天】 LIMIT 分页的性能优化:深分页到底慢在哪?
本文深入剖析MySQL深分页(如`LIMIT 100000,20`)性能瓶颈:本质是OFFSET导致全量扫描与丢弃,页码越深,扫描行数线性增长。详解三种实战优化方案——游标分页(高效稳定,需有序唯一字段)、延迟关联(兼容OFFSET,索引覆盖减回表)、范围分页(极简但场景受限),并附EXPLAIN对比与避坑指南。(239字)
196 6
|
1月前
|
SQL JSON 关系型数据库
【MySQL】《MySQL 索引核心+8.0索引新特性 面试背诵清单》(附:EXPLAIN执行计划完整教程+《MySQL 8.0 索引新特性速查表》)
《MySQL索引核心面试背诵清单》精讲B+树原理、聚簇/二级索引、最左前缀、覆盖索引与失效场景;配套EXPLAIN深度解析(type/key_len/Extra);并系统梳理MySQL 8.0不可见索引、降序索引、函数索引、跳跃扫描等7大新特性,附实战测试模板——助你高效备战技术面试。
|
2月前
|
SQL 关系型数据库 MySQL
EXPLAIN 执行计划:一眼看穿你的SQL慢在哪
数据库小学妹带你轻松掌握SQL性能诊断!通过EXPLAIN查看执行计划,精准识别索引失效、全表扫描(ALL)、key为NULL等瓶颈。聚焦type、key、rows等6个关键字段,结合实战案例与避坑指南(如函数滥用、最左前缀破坏),让优化有的放矢。学完即用,告别盲目调优!