事务是什么?
事务(Transaction)本质上是一组操作的集合,它们要么全部成功执行,要么全部回滚。引入事务的核心目的,是为了保证数据库在并发访问时的一致性、完整性和可靠性。
举个常见的转账场景:A 用户给 B 用户转账 100 元。这涉及两个步骤:A 账户扣款 100,B 账户入账 100。如果第一步完成后,系统因网络波动或宕机导致第二步失败,A 的钱凭空消失,这是绝对不允许的。因此,MySQL 会将这两个操作打包成一个原子单元,要么一起完成,要么都不做。若中途异常,系统会通过日志进行回滚,撤销所有已执行的操作。
在 MySQL 中,事务由多个 SQL 语句组成一个操作单元。提交(commit)意味着所有更改永久生效;回滚(rollback)则意味着恢复到事务开始前的状态。
事务的四大特性
事务遵循 ACID 原则,即原子性、一致性、持久性和隔离性。
原子性(Atomicity)
原子性确保事务是最小的执行单位,不可再分。事务中的操作要么全部成功,要么全部失败。即使执行过程中发生故障,数据库也会通过回滚机制将状态恢复到事务开始前。
一致性(Consistency)
一致性要求事务执行前后,数据库的状态必须从一个一致状态转变到另一个一致状态。这意味着所有数据必须符合完整性约束(如主键、外键)。一旦触发回滚,数据也必须恢复到原来的正确状态,不能出现对不上的情况。
持久性(Durability)
一旦事务提交,它对数据库的更改就是永久性的。即使随后发生系统崩溃或断电,已提交的更改也会保留下来,不会丢失。
隔离性(Isolation)
在并发环境下,多个客户端同时发起事务请求,一个事务的执行不应受到其他事务的干扰。每个事务应像是在独占数据库一样执行,直到它提交或回滚。
并发可能引发的问题
当隔离性不足时,可能会出现以下三类问题:
1. 脏读(Dirty Read)
指一个事务读取了另一个事务尚未提交的数据。如果那个事务最终回滚,当前事务读取到的数据就无效了。
例子: 好比小明抄小强的试卷。小强写完还没检查(未提交),小明就抄走了答案并提交(提交)。结果小强发现错了并修改了答案(回滚),小明拿到的就是错误信息。
解决思路: 当事务 B 查看事务 A 的数据时,需要对 A 的数据加锁,等待 A 确定后再读取。这会降低并发能力,但提高了准确性。
2. 不可重复读(Non-repeatable Read)
指同一个事务内,多次读取同一数据时,由于其他事务提交了修改,导致读取结果不一致。
例子: 读者(事务 B)正在阅读博客内容(事务 A 已发布)。此时作者(事务 C)又修改并发布了一篇新内容。读者刷新页面时发现数据变了,这就是不可重复读。
解决思路: 在读操作期间禁止写操作,对读数据也加上锁,保证前后两次读取一致。
3. 幻读(Phantom Read)
指一个事务查询数据时,其他事务插入了新记录或删除了旧记录,导致该事务查询的结果集发生变化,仿佛出现了'幻影'。
例子: 事务 A 发布第一篇博客。事务 B 查询博客列表。此时事务 C 发布了第二篇博客。事务 B 再次查询时,发现多了一篇博客。
解决思路: 实现串行化操作,暂停其他事务的执行。虽然效率最低,但能最大程度保证数据准确。
隔离级别对比
MySQL 提供了四种隔离级别,用于平衡性能与数据一致性:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 适用场景 |
|---|---|---|---|---|
| 读未提交 (Read Uncommitted) | 是 |


