事务

事务的四个特性 ACID:

  • 原子性(Atomicity):当前事务的操作要么同时成功,要么同时失败。原子性由 undo log 日志来实现。
  • 一致性(Consistent):使用事务的最终目的,由其它3个特性以及业务代码正确逻辑来实现。
  • 隔离性(Isolation):在事务并发执行时,他们内部的操作不能互相干扰。隔离性由 MySQL 的各种锁以及 MVCC 机制来实现。
  • 持久性(Durable):一旦提交了事务,它对数据库的改变就应该是永久性的。持久性由 redo log 日志来实现。

事务处理是一种机制,用来管理必须成批执行的 MySQL 操作,以保证数据库不包含不完整的操作结果。利用事务处理,可以保证一组操作不会中途停止,它们或者作为整体执行,或者完全不执行(除非明确指示)。如果没有错误发生,整组语句提交(写到)数据库表。如果发生错误,则进行回退(撤销)以恢复数据库到某个已知且安全的状态。

关于事务处理需要知道的几个术语:

  • 事务(transaction)指一组 SQL 语句;
  • 回退(rollback)指撤销指定 SQL 语句的过程;
  • 提交(commit)指将未存储的 SQL 语句结果写入数据库表;
  • 保留点(savepoint)指事务处理中设置的临时占位符(place- holder),你可以对它发布回退(与回退整个事务处理不同)

语法

控制事务处理

管理事务处理的关键在于将 SQL 语句组分解为逻辑块,并明确规定数据何时应该回退,何时不应该回退。

下面的语句来标识事务的开始:

START TRANSACTION
BEGIN

BEGINSTART TRANSACTION 差不多,不过 START TRANSACTION 语句后边可以跟随几个修饰符,就是它们几个,START TRANSACTION READ ONLY;START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT;

  • READ ONLY:标识当前事务是一个只读事务,也就是属于该事务的数据库操作只能读取数据,而不能修改数据。
  • READ WRITE:标识当前事务是一个读写事务,也就是属于该事务的数据库操作既可以读取数据,也可以修改数据。
  • WITH CONSISTENT SNAPSHOT:启动一致性读。

ROLLBACK

ROLLBACK 命令用来回退(撤销)MySQL 语句:

select * from ordertotals;
start transaction;
delete from ordertotals;
select * from ordertotals;
rollback;
select * from ordertotals;

先执行一条 SELECT 以显示该表不为空。然后开始一个事务处理,用一条 DELETE 语句删除 ordertotals 中的所有行。另一条 SELECT 语句验证 ordertotals 确实为空。这时用一条 ROLLBACK 语句回退 START TRANSACTION 之后的所有语句,最后一条 SELECT 语句显示该表不为空。

ROLLBACK 只能在一个事务处理内使用(在执行一条 START TRANSACTION 命令之后)

哪些语句不可以回退

CREATEDROP 操作不能回退。事务处理块中可以使用这两条语句,但如果你执行回退,它们不会被撤销。

COMMIT

在事务处理块中,提交不会隐式地进行。需要使用 COMMIT 语句显示提交:

start transaction;
delete from orderitems where order_num = 20005;
delete from orders where order_num = 20005;
commit;

COMMITROLLBACK 语句执行后,事务会自动关闭(将来的更改会隐式提交)。

保留点

简单的 ROLLBACKCOMMIT 语句就可以写入或撤销整个事务处理。复杂的事务处理可能需要部分提交或回退。

为了支持回退部分事务处理,必须能在事务处理块中合适的位置放置占位符。这样,如果需要回退,可以回退到某个占位符。这些占位符称为保留点

创建占位符,可使用 SAVEPOINT 语句:SAVEPOINT delete1;。每个保留点都取标识它的唯一名字,以便在回退时,MySQL 知道要回退到何处。

回退到本例给出的保留点,可执行:ROLLBACK TO delete1;

保留点在事务处理完成(执行一条 ROLLBACKCOMMIT)后自动释放。

mysql> SELECT * FROM account;
+----+--------+---------+
| id | name   | balance |
+----+--------+---------+
|  1 | 狗哥   |      11 |
|  2 | 猫爷   |       2 |
+----+--------+---------+
2 rows in set (0.00 sec)

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> UPDATE account SET balance = balance - 10 WHERE id = 1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SAVEPOINT s1;    # 一个保存点
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM account;
+----+--------+---------+
| id | name   | balance |
+----+--------+---------+
|  1 | 狗哥   |       1 |
|  2 | 猫爷   |       2 |
+----+--------+---------+
2 rows in set (0.00 sec)

mysql> UPDATE account SET balance = balance + 1 WHERE id = 2; # 更新错了
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> ROLLBACK TO s1;  # 回滚到保存点 s1 处
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM account;
+----+--------+---------+
| id | name   | balance |
+----+--------+---------+
|  1 | 狗哥   |       1 |
|  2 | 猫爷   |       2 |
+----+--------+---------+
2 rows in set (0.00 sec)

自动提交

MySQL 中有一个系统变量 autocommit

默认情况下,如果不显式的使用 START TRANSACTION 或者 BEGIN 语句开启一个事务,那么每一条语句都算是一个独立的事务,这种特性称之为事务的自动提交

如果想关闭这种自动提交的功能,可以使用下边两种方法:

  • 显式的的使用 START TRANSACTION 或者 BEGIN 语句开启一个事务。

这样在本次事务提交或者回滚前会暂时关闭掉自动提交的功能。

把系统变量 autocommit 的值设置为 OFF,就像这样:

SET autocommit = OFF;

这样的话,写入的多条语句就算是属于同一个事务了,直到显式的写出 COMMIT 语句来把这个事务提交掉,或者显式的写出 ROLLBACK 语句来把这个事务回滚掉。

隐式提交

当使用 START TRANSACTION 或者 BEGIN 语句开启了一个事务,或者把系统变量 autocommit 的值设置为 OFF 时,事务就不会进行自动提交,但是如果输入了某些语句之后就会悄悄的提交掉,就像输入了 COMMIT 语句了一样,这种因为某些特殊的语句而导致事务提交的情况称为隐式提交

隐式提交的语句包括:

  • 定义或修改数据库对象的数据定义语言(Data definition language,缩写为:DDL):

所谓的数据库对象,指的就是数据库、表、视图、存储过程等等这些东西。当使用 CREATE、ALTER、DROP 等语句去修改这些所谓的数据库对象时,就会隐式的提交前边语句所属于的事务。

  • 隐式使用或修改 mysql 数据库中的表:

当使用 ALTER USERCREATE USERDROP USERGRANTRENAME USERREVOKESET PASSWORD 等语句时也会隐式的提交前边语句所属于的事务。

  • 事务控制或关于锁定的语句:

当在一个事务还没提交或者回滚时就又使用 START TRANSACTION 或者 BEGIN 语句开启了另一个事务时,会隐式的提交上一个事务。

或者当前的 autocommit 系统变量的值为 OFF,我们手动把它调为 ON 时,也会隐式的提交前边语句所属的事务。

  • 加载数据的语句

比如使用 LOAD DATA 语句来批量往数据库中导入数据时,也会隐式的提交前边语句所属的事务。

  • 关于 MySQL 复制的一些语句

使用 START SLAVESTOP SLAVERESET SLAVECHANGE MASTER TO 等语句时也会隐式的提交前边语句所属的事务。

  • 其它的一些语句

使用 ANALYZE TABLECACHE INDEXCHECK TABLEFLUSHLOAD INDEX INTO CACHEOPTIMIZE TABLEREPAIR TABLERESET 等语句也会隐式的提交前边语句所属的事务。

最后更新于