跳至主要內容

初识事务

AruNi_Lu数据库MySQL约 1407 字大约 5 分钟

本文内容

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 操作。

所以,要显示地开启一个事务有两种方式:

  • 使用开启事务的命令,即 BEGINSTART TRANSACTION

  • 执行 SET AUTOCOMMIT=0 来禁止当前会话的自动提交,记得在事务结束位置提交事务。

注意

执行 SET AUTOCOMMIT=0 后,此后的所有 SQL 语句都会包含在一个事务中,哪怕是 select,也要显示 commit。

执行了 BEGIN/START TRANSACTION 命令并不代表事务立马就启动了,只有在执行 DML(CRUD)时,才真正启动了事务。如果想立马启动事务,可以使用 start transaction with consistent snapshot 命令。

来看看事务的控制语句都有哪些:

  • BEGINSTART TRANSACTION:显式开启一个事务;
  • COMMIT:提交事务,保证整个事务中对数据库的所有修改是永久的;
  • ROLLBACK:回滚事务,会结束事务,保证数据库恢复到事务执行前的状态;
  • SAVEPOINT identifier:在事务中创建一个保存点,一个事务中可以有多个 SAVEPOINT;
  • RELEASE SAVEPOINT identifier:删除一个保存点;
  • ROLLBACK TO identifier:把事务回滚到某个标记点。

img

一个简单的事务例子:

-- 开始事务
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:崩溃恢复神器open in new window);
  • 原子性 是通过 undo log(回滚日志)来保证的,undo log 会将事务 SQL 执行前的数据记录下来,后续需要回滚的时候,通过 undo log 即可恢复到事务执行前的状态了(具体看 undo log:世上真有后悔药open in new window);
  • 隔离性 是通过 MVCC(多版本并发控制)和锁机制 来保证的,下一篇文章详细讲解;
  • 一致性 是通过 持久性、原子性、隔离性,以及开发人员的正确编码 来共同保证的。
上次编辑于: