再见二丁目 | yitimo的个人日志

再见二丁目

【翻译】【MySQL文档@13.3.1】START TRANSACTION, COMMIT, 和 ROLLBACK 语法

发布于: 2021-08-31 19:31

此文章久未修订,请自行甄别内容准确性。

START TRANSACTION
    [transaction_characteristic [, transaction_characteristic] ...]

transaction_characteristic: {
    WITH CONSISTENT SNAPSHOT
  | READ WRITE
  | READ ONLY
}

BEGIN [WORK]
COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
SET autocommit = {0 | 1}

这些语法提供了事务(transaction)相关的控制:

默认的 MySQL 会启用 autocommit 模式, 即非事务情况下所有语句都会自动提交, 就好像它们都被包了一层 START TRANSACTION ... COMMIT, 所以你不能使用 ROLLBACK 来回滚改动, 不过语句执行出错时可以实现回滚.

可以使用 START TRANSACTION 语句来禁用一系列语句的自动提交:

START TRANSACTION;
SELECT @A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET summary=@A WHERE type=1;
COMMIT;

使用了 START TRANSACTION 后, 你就需要手动 COMMITROLLBACK 来结束你的事务. 然后 自动提交模式 也会恢复原值.

START TRANSACTION 语句支持一些修饰语来控制你的事务, 多个修饰语用逗号隔开:

MySQL 对 InnoDB 索引的表, 在只读事务中的查询提供了额外优化. 在不能自动识别为只读模式的情况下可以手动开启来得到这些优化.

默认的访问模式是 READ/WRITE 读写模式. 同一个语句不支持同时制定只读和读写模式.

在只读模式下, 支持使用 DML 语句来修改使用 TEMPORARY 关键词创建的临时表. DDL语句的修改、持久化表则是不被允许的.

更多关于事务访问模式的信息详见 13.3.7.

如果开启了只读系统变量, START TRANSACTION READ WRITE 语句需要connection 的管理权限.

重要: 很多MySQL客户端(比如 JDBC)都封装并提供了他们自己的方法来开启事务, 而不需要直接使用 START TRANSACTION 语句.

想要显式禁用自动提交模式, 使用以下语句:

SET autocommit=0;

当设置值为 0 来禁用自动提交后, 对于事务安全的表的改动都不会立即生效, 你必须手动 COMMIT 来使其生效, 或 ROLLBACK 来回滚改动.

autocommit 是一个session级的变量, 故每个session都要设置. 想要禁用所有新连接的自动提交的话, 需要设置到 autocommit 的系统变量.

BEGINBEGIN WORKSTART TRANSACTION 的别名, 用来初始化一个事务. START TRANSACTION 是一个标准SQL语句, 是开启一个 ad-hoc 事务和修改器的推荐方式, 而 BEGIN 不是.

这里的 BEGIN 语法跟 BEGIN ... END 混用的情况不同, 后者不会开始一个事务.

注意: 在所有存储的程序里(比如 过程、函数、触发器和事件), 会认为 BEGINBEGIN ... END 块的开始部分. 故请使用 START TRANSACTION 语法.

可选的 WORK 关键字也支持 COMMITROLLBACK, 用的是 CHAINRELEASE. 这两个语法用来提供事务结束阶段的更多控制. 系统变量 completion type 定义了默认的结束行为.

AND CHAIN语法能在当前事务结束时立即开启一个新事务, 新的事物和原事务拥有相同的隔离等级、读写访问权限. RELEASE 语法使服务在当前事务结束后断连当前session. 还有 NO 关键词来禁用 CHAIN/RELEASE 行为, 当想系统默认开启completion_type 配置时会用到.

开始一个新事务会使所有正在pending的事务被提交, 详见 13.3.3.

开始一个新事务同时还会使捕获的表锁被释放, 就好像你自己执行了 UNLOCK TABLES. 开启新事务不会释放全局的读锁(FLUSH TABLES WITH READ LOCK得到的).

为了最好的结果, 事务应该只被单事务安全的存储引擎管理的表来使用. 否则可能会有以下问题:

每个事务都被存储在一个二进制日志里, 直到 COMMIT. 被回滚的事务不会被记录. (例外: 非事务的表不能被回滚, 如果被回滚的事务里包含了非事务表的改动, 整个事务会在 ROLLBACK 语句后被记录, 来确保非事务表的改动是重复的.)

你可以用 SET TRANSACTION 语句来修改事务的隔离等级和访问模式. 详见 13.3.7.

回滚是一个慢操作, 且可能发生用户意料之外的行为. 因此, SHOW PROCESSLIST 可以用来显示session的State列中的回滚, 这对隐式回滚和主动回滚都有效.

注意: 在 MySQL 8.0 里, BEGIN, COMMIT 和 ROLLBACK 不受 --replicate-do-db--replicate-ignore-db 规则影响.

InnoDB 完成了一次事务的回滚, 这次事务设置的所有锁都会被释放. 如果事务里的单个SQL语句由于错误而回滚了, 这条语句里的锁会在事务还存在时保留. 这是因为 InnoDB 存储不知道行锁究竟是哪条语句设置的.

如果事务里的一个select语句调用了存储方法, 且存储方法里的一条语句时报了, 这次事务会回滚. 如果后续事务又执行了ROLLBACK, 整个事务都会被回滚.

原文链接

https://dev.mysql.com/doc/refman/8.0/en/commit.html