MySQL: 自动提交标志打开但事务仍然可以回滚
MySQL: autocommit flag is on but transaction still can rollback
我使用的是 MariaDB 版本 10.3.13
。我上次检查时,autocommit
标志已打开。
MariaDB> SHOW VARIABLES WHERE Variable_name='autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
正如我在文档中读到的那样,当自动提交开启时,您无法按规定回滚事务 here
By default, MySQL runs with autocommit mode enabled. This means that
as soon as you execute a statement that updates (modifies) a table,
MySQL stores the update on disk to make it permanent. The change
cannot be rolled back.
所以我写了一个小脚本来测试。首先,我开始交易并更新一些数据:
BEGIN;
UPDATE foo SET year = 2019 WHERE id = 1;
Query OK, 1 row affected (0.000 sec)
Rows matched: 1 Changed: 1 Warnings: 0
看来我已经完成了。然后我回滚:
ROLLBACK;
Query OK, 0 rows affected (0.005 sec)
然后我再次查看更新记录,我看到数据没有变化。这很奇怪,因为我认为无论如何数据都会改变,因为 autocommit
标志已打开。
请解释原因。
谢谢
BEGIN
是禁用 autocommit
.
效果的显式事务开始
自动提交适用于 SQL 不是明确事务性的。
即使 autocommit
开启,如果您使用 BEGIN
或 START TRANSACTION
,它会暂时中止每个语句的自动提交,直到您完成事务。
您引用了手册页 https://dev.mysql.com/doc/refman/8.0/en/commit.html,其中继续解释:
To disable autocommit mode implicitly for a single series of statements, use the START TRANSACTION statement:
With START TRANSACTION, autocommit remains disabled until you end the transaction with COMMIT or ROLLBACK. The autocommit mode then reverts to its previous state.
(强调我的)
换句话说,您在 BEGIN
或 START TRANSACTION
之后执行的语句 不会 自动提交。这是预期的。
虽然前面的答案是正确的,但让我指出另一个角度。
如果你运行一个billion-rowUPDATE
(这需要几个小时),然后拔掉电脑的插头,UPDATE
将部分完成。重新启动计算机(和 MySQL)后,会发生什么?在 MyISAM 中,有些行会被更新,有些不会。但是对于 InnoDB,它将 ROLLBACK
部分完成 UPDATE
(并且可能需要更多时间才能完成)。
因此,手册中的引述不仅含糊不清(正如其他答案所指出的),而且 'literally' 不正确。在我的示例中,更改 can 和 was 回滚。
我喜欢这样表述:
Autocommit=ON
, when not otherwise in a transaction, is equivalent to wrapping the statement in BEGIN
and COMMIT
. That is, the statement is performed atomically.
我提交了 http://bugs.mysql.com/95414 .
我使用的是 MariaDB 版本 10.3.13
。我上次检查时,autocommit
标志已打开。
MariaDB> SHOW VARIABLES WHERE Variable_name='autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
正如我在文档中读到的那样,当自动提交开启时,您无法按规定回滚事务 here
By default, MySQL runs with autocommit mode enabled. This means that as soon as you execute a statement that updates (modifies) a table, MySQL stores the update on disk to make it permanent. The change cannot be rolled back.
所以我写了一个小脚本来测试。首先,我开始交易并更新一些数据:
BEGIN;
UPDATE foo SET year = 2019 WHERE id = 1;
Query OK, 1 row affected (0.000 sec)
Rows matched: 1 Changed: 1 Warnings: 0
看来我已经完成了。然后我回滚:
ROLLBACK;
Query OK, 0 rows affected (0.005 sec)
然后我再次查看更新记录,我看到数据没有变化。这很奇怪,因为我认为无论如何数据都会改变,因为 autocommit
标志已打开。
请解释原因。 谢谢
BEGIN
是禁用 autocommit
.
自动提交适用于 SQL 不是明确事务性的。
即使 autocommit
开启,如果您使用 BEGIN
或 START TRANSACTION
,它会暂时中止每个语句的自动提交,直到您完成事务。
您引用了手册页 https://dev.mysql.com/doc/refman/8.0/en/commit.html,其中继续解释:
To disable autocommit mode implicitly for a single series of statements, use the START TRANSACTION statement:
With START TRANSACTION, autocommit remains disabled until you end the transaction with COMMIT or ROLLBACK. The autocommit mode then reverts to its previous state.
(强调我的)
换句话说,您在 BEGIN
或 START TRANSACTION
之后执行的语句 不会 自动提交。这是预期的。
虽然前面的答案是正确的,但让我指出另一个角度。
如果你运行一个billion-rowUPDATE
(这需要几个小时),然后拔掉电脑的插头,UPDATE
将部分完成。重新启动计算机(和 MySQL)后,会发生什么?在 MyISAM 中,有些行会被更新,有些不会。但是对于 InnoDB,它将 ROLLBACK
部分完成 UPDATE
(并且可能需要更多时间才能完成)。
因此,手册中的引述不仅含糊不清(正如其他答案所指出的),而且 'literally' 不正确。在我的示例中,更改 can 和 was 回滚。
我喜欢这样表述:
Autocommit=ON
, when not otherwise in a transaction, is equivalent to wrapping the statement inBEGIN
andCOMMIT
. That is, the statement is performed atomically.
我提交了 http://bugs.mysql.com/95414 .