数据库事务是一组要么全部执行成功、要么全部不执行的数据库操作集合,目的是保证数据库在并发操作和异常情况下的数据一致性。MySQL作为常用的关系型数据库,对事务提供了完整的支持,其事务实现既遵循数据库事务的通用规范,也有自身的独特设计。

数据库事务的核心:ACID特性
所有关系型数据库的事务都需要满足ACID四大特性,这是事务有效性的基础:
- 原子性(Atomicity):事务中的所有操作是一个不可分割的整体,要么全部完成,要么全部回滚,不会出现部分执行的情况。
- 一致性(Consistency):事务执行前后,数据库的状态必须符合预设的业务规则,比如转账前后总金额不变。
- 隔离性(Isolation):多个事务并发执行时,一个事务的执行不能被其他事务干扰,不同事务之间的操作相互隔离。
- 持久性(Durability):事务一旦提交,其对数据库的修改就会永久保存,即使数据库发生故障也不会丢失。
MySQL事务的隔离级别
MySQL支持SQL标准定义的四种事务隔离级别,不同隔离级别对隔离性的支持程度不同,也会对应不同的并发问题:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交(READ UNCOMMITTED) | 可能 | 可能 | 可能 |
| 读已提交(READ COMMITTED) | 不可能 | 可能 | 可能 |
| 可重复读(REPEATABLE READ) | 不可能 | 不可能 | 可能(InnoDB通过MVCC基本避免) |
| 串行化(SERIALIZABLE) | 不可能 | 不可能 | 不可能 |
MySQL的默认隔离级别是可重复读,可以通过以下语句查看和修改当前会话的隔离级别:
-- 查看当前事务隔离级别 SELECT @@transaction_isolation; -- 设置当前会话隔离级别为读已提交 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
MySQL事务的基本操作
MySQL中默认开启自动提交,即每条SQL语句都会自动作为一个独立事务提交。如果需要手动控制事务,需要先关闭自动提交:
-- 关闭自动提交 SET autocommit = 0; -- 开启事务(也可以直接用BEGIN) START TRANSACTION; -- 执行一组操作 UPDATE account SET balance = balance - 100 WHERE id = 1; UPDATE account SET balance = balance + 100 WHERE id = 2; -- 提交事务,持久化修改 COMMIT; -- 如果出现异常,回滚事务,撤销所有操作 ROLLBACK;
MySQL事务的实现原理
原子性和持久性的实现:redo log和undo log
MySQL的InnoDB存储引擎通过redo log(重做日志)保证事务的持久性:事务执行过程中,所有修改会先写入redo log,再异步刷入磁盘数据页,即使数据库宕机,重启后也可以通过redo log恢复未刷盘的数据。
undo log(回滚日志)则用来保证原子性:每次修改数据前,都会记录对应的undo log,事务回滚时可以通过undo log将数据恢复到修改前的状态,同时undo log也支持MVCC的多版本读。
隔离性的实现:锁机制和MVCC
MySQL通过锁机制解决写写冲突:写操作会对涉及的数据行加排他锁,其他事务无法同时对这些行加锁或修改,保证写操作的隔离性。
对于读写冲突,InnoDB采用MVCC(多版本并发控制)机制:每行数据会有两个隐藏字段trx_id(最后修改该行的事务ID)和roll_pointer(指向该行上一个版本的undo log指针),查询时根据当前事务的ID和Read View(读视图),判断应该读取哪个版本的数据,不需要加锁就能实现非阻塞读,提升了并发性能。
数据库事务与MySQL事务的关联
数据库事务是通用的概念,定义了事务的ACID特性和隔离级别标准,而MySQL事务是对这个标准的实现。MySQL的可重复读隔离级别在标准SQL的基础上,通过MVCC机制进一步避免了幻读问题,同时提供了redo log、undo log等特有的实现方式,来保证事务特性的落地。开发者在使用MySQL时,只需要遵循事务的基本操作规范,就能利用MySQL的事务能力保证数据一致性。