Mysql START TRANSACTION、COMMIT 和 ROLLBACK 语句

来自泡泡学习笔记
BrainBs讨论 | 贡献2024年7月22日 (一) 16:33的版本 (创建页面,内容为“这些语句提供了对事务使用的控制: <syntaxhighlight lang="sql"> 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} </syntaxhighlight> * START TRANSACTION 或 BEGIN 开启一个新事务。 * COMMIT 提交…”)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳到导航 跳到搜索

这些语句提供了对事务使用的控制:

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}
  • START TRANSACTION 或 BEGIN 开启一个新事务。
  • COMMIT 提交当前事务,使其更改永久生效。
  • ROLLBACK 回滚当前事务,取消其更改。
  • SET autocommit 禁用或启用当前会话的默认自动提交模式。


默认情况下,MySQL 在启用自动提交模式下运行。这意味着,当不在事务内部时,每个语句都是原子性的,就好像它们被 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 后,自动提交将保持禁用状态,直到您使用 COMMIT 或 ROLLBACK 结束事务。然后,自动提交模式将恢复到其先前的状态。

START TRANSACTION 允许使用几个修饰符来控制事务特征。要指定多个修饰符,请用逗号分隔它们。


WITH CONSISTENT SNAPSHOT 修饰符为能够支持的存储引擎启动一致读。这仅适用于 InnoDB。其效果与发出 START TRANSACTION 后跟从任何 InnoDB 表进行的 SELECT 相同。WITH CONSISTENT SNAPSHOT 修饰符不会更改当前事务隔离级别,因此只有当当前隔离级别允许一致读取时,它才提供一致的快照。允许一致读取的唯一隔离级别是 REPEATABLE READ。对于所有其他隔离级别,WITH CONSISTENT SNAPSHOT 子句将被忽略。当 WITH CONSISTENT SNAPSHOT 子句被忽略时会生成一个警告。


READ WRITE 和 READ ONLY 修饰符设置事务访问模式。它们允许或禁止对事务中使用的表进行更改。READ ONLY 限制可防止事务修改或锁定其他事务可见的事务表和非事务表;但事务仍可以修改或锁定临时表。

当已知事务为只读时,MySQL 对 InnoDB 表上的查询启用额外的优化。指定 READ ONLY 可确保在无法自动确定只读状态的情况下应用这些优化。

如果未指定访问模式,则应用默认模式。除非已更改默认值,否则为读/写。在同一语句中同时指定 READ WRITE 和 READ ONLY 是不允许的。

在只读模式下,仍然可以使用 DML 语句更改使用 TEMPORARY 关键字创建的表。与永久表一样,不允许使用 DDL 语句进行更改。

如果启用了 read_only 系统变量,使用 START TRANSACTION READ WRITE 显式启动事务需要 CONNECTION_ADMIN 权限(或已弃用的 SUPER 权限)。

重要

许多用于编写 MySQL 客户端应用程序的 API(例如 JDBC)提供了它们自己的启动事务的方法,可以(有时应该)使用这些方法,而不是从客户端发送 START TRANSACTION 语句。


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

SET autocommit=0;


在通过将 autocommit 变量设置为 0 来禁用自动提交模式后,对事务安全表(例如 InnoDB 或 NDB 表)的更改不会立即永久生效。您必须使用 COMMIT 将更改存储到磁盘,或使用 ROLLBACK 忽略更改。

autocommit 是一个会话变量,必须为每个会话进行设置。


BEGIN 和 BEGIN WORK 作为 START TRANSACTION 的别名用于启动事务。START TRANSACTION 是标准的 SQL 语法,是启动临时事务的推荐方式,并且允许使用 BEGIN 不允许使用的修饰符。

BEGIN 语句与启动 BEGIN... END 复合语句时使用的 BEGIN 关键字不同。后者不会启动事务。

注意:

在所有存储程序(存储过程和函数、触发器和事件)中,解析器将 BEGIN [WORK] 视为 BEGIN... END 块的开始。在这种情况下,请使用 START TRANSACTION 开始事务。


可选的 WORK 关键字在 COMMIT 和 ROLLBACK 中受支持,CHAIN 和 RELEASE 子句也是如此。CHAIN 和 RELEASE 可用于对事务完成进行额外控制。completion_type 系统变量的值决定了默认的完成行为。


AND CHAIN 子句会导致当前事务结束后立即开始新事务,新事务具有与刚结束的事务相同的隔离级别。新事务还使用与刚结束的事务相同的访问模式(READ WRITE 或 READ ONLY)。RELEASE 子句会导致服务器在终止当前事务后断开当前客户端会话。包含 NO 关键字可以抑制 CHAIN 或 RELEASE 完成,如果 completion_type 系统变量默认设置为导致链接或释放完成,这会很有用。

开始事务会导致任何未决事务被提交。

开始事务还会导致通过 LOCK TABLES 获取的表锁被释放,就好像您执行了 UNLOCK TABLES 一样。开始事务不会释放通过 FLUSH TABLES WITH READ LOCK 获取的全局读锁。


为获得最佳效果,应仅使用由单个事务安全存储引擎管理的表来执行事务。否则,可能会出现以下问题:

  • 如果您使用来自多个事务安全存储引擎(例如 InnoDB)的表,并且事务隔离级别不是 SERIALIZABLE,则当一个事务提交时,使用相同表的另一个正在进行的事务可能只会看到第一个事务所做的部分更改。也就是说,使用混合引擎时事务的原子性不能保证,可能会导致不一致。(如果混合引擎事务很少,可以根据需要使用 SET TRANSACTION ISOLATION LEVEL 在每个事务的基础上将隔离级别设置为 SERIALIZABLE。)
  • 如果在事务中使用非事务安全的表,则对这些表的更改会立即存储,而不管自动提交模式的状态如何。
  • 如果在事务中更新了非事务表后发出 ROLLBACK 语句,则会出现 ER_WARNING_NOT_COMPLETE_ROLLBACK 警告。对事务安全表的更改会回滚,但对非事务安全表的更改不会。
  • 每个事务在提交时会在二进制日志中作为一个块存储。回滚的事务不会被记录。(例外情况:对非事务表的修改无法回滚。如果回滚的事务包括对非事务表的修改,则整个事务会被记录,并在末尾加上 ROLLBACK 语句,以确保对非事务表的修改被复制。)
  • 您可以使用 SET TRANSACTION 语句更改事务的隔离级别或访问模式。
  • 回滚可能是一个缓慢的操作,可能会在未得到用户明确要求的情况下隐式发生(例如,发生错误时)。因此,SHOW PROCESSLIST 在 State 列中为会话显示“Rolling back”,不仅是使用 ROLLBACK 语句执行的显式回滚,还包括隐式回滚。

注意:

在 MySQL 8.4 中,BEGIN、COMMIT 和 ROLLBACK 不受 --replicate-do-db 或 --replicate-ignore-db 规则的影响。

  • 当 InnoDB 对事务进行完全回滚时,事务设置的所有锁都会被释放。如果事务中的单个 SQL 语句由于错误(例如重复键错误)而回滚,则在事务仍处于活动状态时,该语句设置的锁将被保留。这是因为 InnoDB 以一种格式存储行锁,以至于之后无法知道哪个锁是由哪个语句设置的。
  • 如果事务中的 SELECT 语句调用了存储函数,并且存储函数中的语句失败,则该语句回滚。如果随后对事务执行 ROLLBACK,则整个事务回滚。