何为事务?
事务(Transaction)是一组操作的集合,它们要么全部执行成功,要么全部失败回滚。引入事务主要是为了保证数据库的一致性、完整性和可靠性。
试想一个转账场景:A 用户给 B 用户转 100 元。这涉及两个步骤:A 扣款 100,B 入账 100。如果 A 扣款成功后系统崩溃导致 B 没收到钱,资金就凭空消失了。这种情况绝不允许发生。因此,MySQL 会将这两个操作打包成一个整体,具备'原子性'。一旦中途出错,所有操作都会撤销(回滚),恢复到初始状态。MySQL 依靠日志记录每一步操作,确保在故障发生时能够还原。
在 MySQL 中,事务是一个 SQL 语句的操作单元。成功则提交(commit),失败则回滚(rollback)。这提供了更强的错误恢复能力,并保障并发访问下的一致性。
事务的四大特性
事务遵循 ACID 原则:原子性(Atomicity)、一致性(Consistency)、持久性(Durability)、隔离性(Isolation)。
原子性
原子性意味着事务是不可分割的最小执行单位。要么全做,要么全不做。即使执行过程中发生故障,数据库也会通过回滚将状态恢复到事务开始前。
一致性
事务执行前后,数据库必须从一个一致状态转变到另一个一致状态。这意味着所有完整性约束(如主键、外键)都必须被遵守。如果触发回滚,数据必须回到原来的样子,不能出现对不上的情况。
持久性
一旦事务提交,更改就是永久性的。即便系统崩溃或断电,已提交的数据也不会丢失。
隔离性
在并发环境下,多个客户端同时发起请求,一个事务的执行不应受其他事务干扰。每个事务应感觉像是在独占数据库一样执行,直到提交或回滚。
但在并发中,可能会遇到以下问题:
脏读
一个事务读取了另一个事务尚未提交的数据。如果对方事务后来回滚了,当前事务读到的就是无效数据。
例子: 小明抄袭小强的试卷。小强写完交卷前修改了答案,但小明已经抄到了旧答案上。结果小强改对了,小明却拿了错分。 核心逻辑: 只有当对方确认不再修改(提交)后,才能读取其数据。
解决方案: 当事务 B 读取事务 A 的数据时,对 A 加锁。B 必须等待 A 确定下来才能查看。这降低了并发效率,但提高了数据准确性和隔离性。
不可重复读
同一个事务内,多次读取同一数据,结果不一致。通常是因为其他事务在此期间修改并提交了这个数据。
例子: 我们发布了一篇博客(事务 A)。读者去阅读(事务 B)。此时我们又修改了内容并发布(事务 C)。读者刷新页面发现内容变了,这就是不可重复读。
解决方案: 在读操作期间锁定数据,防止其他事务修改。即'读的时候不能写',保证前后两次读取一致。
幻读
一个事务查询时,其他事务插入了新记录或删除了记录,导致查询结果集发生变化,仿佛出现了'幻影'。
例子: 事务 A 发布第一篇博客。事务 B 查询博客列表。此时事务 C 发布了第二篇博客。B 再次查询时,发现多了一篇,这就是幻读。
解决方案: 实现串行化操作。在执行事务时暂停其他操作,没有并发,效率最低但隔离性最高,数据最准确。
隔离级别对比
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 适用场景 |
|---|---|---|---|---|
| 读未提交(Read Uncommitted) | 是 | 是 | 是 | 高并发、无需完全一致性 |
| 读已提交(Read Committed) | 否 | 是 | 是 | 实时性要求较高 |
| 可重复读(Repeatable Read) | 否 | 否 |


