MySQL事务是一组逻辑操作单元,要么全部执行成功,要么全部不生效。InnoDB存储引擎完整支持事务,其特点直接决定了我们在高并发系统中处理资金、订单等敏感数据时的可靠性。事务并非单纯“加个begin和commit”,背后有一整套机制支撑。

一、原子性(Atomicity)
原子性是指事务内的所有操作是一个不可分割的整体。如果事务中某一条SQL执行失败,已经执行的部分必须被撤销,数据库回到事务开始前的状态。MySQL依靠undo log来实现这一点:每当数据被修改前,旧值会写入undo log,回滚时按相反顺序重放这些记录即可还原。
例如用户转账场景,从A扣钱和给B加钱必须同时成功。若第二步崩溃,原子性保证第一步扣款也被回滚,不会出现钱“消失”的情况。下面是一段示意代码:
START TRANSACTION; UPDATE account SET balance = balance - 100 WHERE user = 'A'; UPDATE account SET balance = balance + 100 WHERE user = 'B'; COMMIT;
若在两条更新之间发生错误,执行ROLLBACK就会利用undo log恢复A的余额。原子性避免了半成品数据对外可见,是业务正确性的底线。
二、一致性(Consistency)
一致性要求事务必须将数据库从一种合法状态转换到另一种合法状态。它不仅依赖数据库约束(如主键、外键、唯一索引),也依赖应用层逻辑。比如账户总额在转账前后应保持不变,这种业务规则由开发者在事务中保证。
MySQL自身通过约束和事务机制防止非法写入,但一致性更偏向“综合结果”。以下代码展示了利用检查机制辅助一致性的思路:
-- 建表时限制余额不能为负 CREATE TABLE account ( user VARCHAR(20) PRIMARY KEY, balance INT CHECK (balance >= 0) );
当余额约束被违反时,事务会因错误而中止,从而维护数据逻辑上的完整。一致性是ACID的最终目标,其他三个特点都是为它服务的。
三、隔离性(Isolation)
隔离性描述多个并发事务互不影响程度。MySQL提供四种隔离级别:读未提交、读已提交、可重复读、串行化。默认是可重复读,通过MVCC和锁机制避免脏读与不可重复读,配合间隙锁抑制幻读。
不同级别在性能与安全性上权衡不同。下表列出常见现象:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 | 可能 | 可能 | 可能 |
| 读已提交 | 否 | 可能 | 可能 |
| 可重复读 | 否 | 否 | 否(InnoDB) |
| 串行化 | 否 | 否 | 否 |
实际开发中,若报表类查询对实时性要求不高,可适当降低隔离级别减少锁等待;金融扣款则建议维持默认可重复读并显式加锁。隔离性直接关系并发系统的稳定。
四、持久性(Durability)
持久性意味着一旦事务提交,其结果永久保存,即使系统断电或崩溃也不丢失。InnoDB使用redo log实现:数据先写内存和redo log缓冲,再异步刷盘。崩溃恢复时重放redo log即可复原已提交页。
以下伪代码体现提交时的日志顺序:
事务提交: 1. 将修改写入redo log(prepare) 2. 写binlog 3. redo log提交标记(commit) 4. 后台线程刷脏页到数据文件
这种两阶段写法保证了即使宕机,也能通过日志决出已提交事务并恢复。持久性让MySQL适合作为核心系统的可信数据源。
五、总结与运用建议
MySQL事务的ACID特点相互协作:原子性兜底操作完整性,一致性定义正确状态,隔离性处理并发,持久性守护结果。在MyISAM等不支持事务的引擎中,这些特点天然缺失,因此关键业务务必选用InnoDB。
写代码时应缩小事务范围,避免长事务占用锁与undo空间;对只读场景可用START TRANSACTION READ ONLY提升效率。理解特点才能用对事务,而非盲目包裹SQL。