初识事务
本文内容
1. 什么是事务?
在 MySQL 数据库中,事务是指 对数据库表的一系列操作都是一个单独的工作单元。主要用于在批量操作多个表时,需要让这些操作成为一个独立的工作单元,保证它们要么全部执行,要么全部不执行。
举个例子,现在有三个表 user、video、post,我们在删除 user 的时候,希望把该 user 的 video 和 post 一并删除,这将涉及到三个表的 delete 操作(由于 user 与 video、post 是一对多的关系,所以 video 和 post 又涉及多个 delete 操作),这三个操作就需要使用事务,否则可能出现 user 被删除,而其 video/post 没被删除的情况。
MySQL 中事务是在存储引擎实现的,MySQL 支持多种引擎,但不是都支持事务,比如 MyISAM 就不支持事务,而现在常用的 InnoDB 是支持的。我下面讲的事务都是基于 InnoDB 的。
2. 事务控制语句
在 MySQL 中会默认开启 隐式事务,即在执行 insert、update 或 delete 语句的时候,会自动开启一个事务来执行这些操作,执行完后默认是会 自动提交 的,即执行完一句 SQL 后会马上执行 COMMIT 操作。
所以,要显示地开启一个事务有两种方式:
使用开启事务的命令,即
BEGIN
或START TRANSACTION
;执行
SET AUTOCOMMIT=0
来禁止当前会话的自动提交,记得在事务结束位置提交事务。
注意
执行 SET AUTOCOMMIT=0
后,此后的所有 SQL 语句都会包含在一个事务中,哪怕是 select,也要显示 commit。
执行了 BEGIN/START TRANSACTION
命令并不代表事务立马就启动了,只有在执行 DML(CRUD)时,才真正启动了事务。如果想立马启动事务,可以使用 start transaction with consistent snapshot
命令。
来看看事务的控制语句都有哪些:
BEGIN
或START TRANSACTION
:显式开启一个事务;COMMIT
:提交事务,保证整个事务中对数据库的所有修改是永久的;ROLLBACK
:回滚事务,会结束事务,保证数据库恢复到事务执行前的状态;SAVEPOINT identifier
:在事务中创建一个保存点,一个事务中可以有多个 SAVEPOINT;RELEASE SAVEPOINT identifier
:删除一个保存点;ROLLBACK TO identifier
:把事务回滚到某个标记点。
一个简单的事务例子:
-- 开始事务
BEGIN; -- or START TRANSACTION;
-- 执行一些 SQL 语句
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
-- 判断是否要提交还是回滚
IF (条件) THEN
COMMIT; -- 提交事务
ELSE
ROLLBACK; -- 回滚事务
END IF;
3. 事务的四大特性
事务必须满足 ACID(Atomicity、Consistency、Isolation、Durability),即原子性、一致性、隔离性、持久性。它们的含义分别如下:
- Atomicity 原子性:一个事务中的所有操作是原子的,要么全部完成,要么全部不完成,不会结束在某个中间环节。如果事务过程中发生了 任一错误,则整个事务会被 回滚,以还原到原始状态;
- Consistency 一致性:一个事务操作前和操作后,数据都必须满足 完整性约束,这个完整性约束包括 实体完整性(满足字段的约束条件)、参照完整性(确保外键关联的表的键存在于被关联的表中)、用户自定义的完整性(业务逻辑,比如转账,汇款方减 100,保证收款方加 100)等;
- Isolation 隔离性:在 多个事务并发执行时,隔离性可以保证其操作 不会互相影响,每个事务都有一个 独立完整的数据空间,对其他并发事务是隔离的。隔离的效果根据不同的 隔离级别 有所不同;
- Durability 持久性:一个事务结束后,对数据的修改就是永久的,即使数据库系统发生故障 数据也不会丢失。
4. ACID 分别靠什么保证?
MySQL 的 InnoDB 存储引擎支持事务,那么它是通过什么来保证事务的 ACID 的呢?
- 持久性 是通过 redo log(重做日志)来保证的,redo log 有 crash-safe 的能力,即可以保证即使系统断电崩溃,数据也是不会丢失的(具体看 redo log:崩溃恢复神器);
- 原子性 是通过 undo log(回滚日志)来保证的,undo log 会将事务 SQL 执行前的数据记录下来,后续需要回滚的时候,通过 undo log 即可恢复到事务执行前的状态了(具体看 undo log:世上真有后悔药);
- 隔离性 是通过 MVCC(多版本并发控制)和锁机制 来保证的,下一篇文章详细讲解;
- 一致性 是通过 持久性、原子性、隔离性,以及开发人员的正确编码 来共同保证的。