文章

MySQL 事务

数据库事务

事务是一个抽象的概念,它对应着一个或多个数据库操作,这些操作要么全部成功,要么全部失败。事务有四大特性,即 ACID

事务特性

说明

实现方式

原子性(Atomicity)

一个事务中的所有操作要么全部成功,要么全部失败回滚

由 undo log 来保证

一致性(Consistency)

事务在执行过程中可能改变数据状态,但必须确保数据从一个一致性状态到另一个一致性状态

由其他 3 个特性和正确的业务代码逻辑来保证

隔离性(Isolation)

多个事务并发执行时,每个事务的操作应该与其他事务隔离开来,互不干扰(隔离级别定义了一个事务在并发环境看到其他事务的程度)

由 MySQL 的各种锁和 MVCC 来保证

持久性(Durability)

一旦提交了事务,它所做的修改应该永久保存在数据库中,即使系统故障或重启也不会丢失

由redo log来保证

事务可以分成这么几个状态: 

事务状态

说明

活跃的(active)

事务对应的数据库操作正在执行中

部分提交的(partially committed)

事务所有数据库操作执行完成,但是修改的数据还没有刷新到磁盘

提交的(committed)

事务所有数据库操作执行完成,并且已经把修改的数据刷新到磁盘

中止的(aborted)

对于处在 failed 状态的事务,当把回滚操作执行完后,该事务状态会变为 aborted

失败的(failed)

对于处在 active 或 partially committed 状态的事务,当遇到错误或者被手动停止而无法继续执行时,该事务状态会变为 failed

事务的这几个状态的流转路径如下:

从图中可以看出,当事务处于 committed 或者 aborted 状态时,这个事务的生命周期才算结束。对于 committed 的事务来说,该事务对数据库所做的修改将永久生效;对于 aborted 状态的事务,该事务对数据库所做的所有修改都会被回滚到没执行该事务之前的状态。

 

MySQL 事务语法

在常见的 MySQL 存储引擎中,InnoDB 支持事务,MyISAM 不支持事务。下面我们学习下 MySQL 事务的语法:

开启事务

MySQL 支持两种方式开启事务:

(1) BEGIN

BEGIN;
<要在事务中执行的 SQL 语句>

(2) START TRANSACTION

START TRANSACTION;  -- 默认访问模式是 READ WRITE 读写模式
<要在事务中执行的 SQL 语句>

START TRANSACTION 后面还可以跟几个修饰符(READ ONLY、READ WRITE、WITH CONSISTENT SNAPSHOT):

-- 开启一个只读事务
START TRANSACTION READ ONLY;
-- 开启一个读写事务
START TRANSACTION READ WRITE;
-- 开启一个只读事务和一致性读
START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT;
-- 开启一个读写事务和一致性读
START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT;

提交事务

手动提交事务

使用 COMMIT 语句可以手动提交事务,如:

BEGIN;
<要在事务中执行的 SQL 语句>
COMMIT;

自动提交事务

MySQL 有一个 autocommit 系统变量控制是否自动提交事务:

mysql> SHOW VARIABLES LIKE 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+

可以看到 autocommit 默认为 ON 开启自动提交,如果不显式使用 BEGIN 或 START TRANSACTION 开启事务,那么每一条语句都会开启一个独立的事务并自动提交。

隐式提交事务

有些特殊的语句会导致事务提交,这就是隐式提交。常见的会导致隐式提交的语句有:

  1. DDL 语句(操作数据库、表、视图、存储过程等),如 CREATE TABLE、ALTER TABLE、CREATE PROCEDURE

  2. 隐式使用或修改 mysql 数据库中的表,如 ALTER USER、GRANT、SET PASSWORD

  3. 当前事务未提交或回滚时就又使用 START TRANSACTION 或 BEGIN 开启事务 

  4. 锁定相关语句,如 LOCK TABLES、UNLOCK TABLES

  5. 加载数据的语句,如 LOAD DATA

  6. 关于 MySQL 复制的一些语句,如 START SLAVE、STOP SLAVE、RESET SLAVE、CHANGE MASTER TO

  7. 一些其他语句,如 ANALYZE TABLE、CACHE INDEX、CHECK TABLE、FLUSH、LOAD INDEX INTO CACHE、OPTIMIZE TABLE、REPAIR TABLE、RESET

回滚事务

如果事务在执行过程中遇到了某些错误而无法继续执行的话,事务会自动回滚。同时,MySQL 也支持使用 ROLLBACK 语句手动回滚事务,如:

BEGIN;
<要在事务中执行的 SQL 语句>
ROLLBACK;

但是有时候我们不想回滚到事务开启时的最初状态,而是想回滚到中间的某个状态,为此 MySQL 引入了一个保存点(savepoint)的概念。有了保存点之后,使用 ROLLBACK 的时候可以指定回滚到哪个保存点,语法如下:

SAVEPOINT <保存点名称>;  -- 创建保存点
ROLLBACK TO <保存点名称>;  -- 回滚到某个保存点

如果想要删除保存点,可以执行这个语句:

RELEASE SAVEPOINT <保存点名称>;

License:  CC BY 4.0