简体   繁体   English

MySQL:自动提交标志已打开但事务仍可以回滚

[英]MySQL: autocommit flag is on but transaction still can rollback

I am using MariaDB version 10.3.13 . 我使用的是MariaDB版本10.3.13 The last time I checked, autocommit flag is on. 我最后一次检查时, autocommit标志已打开。

MariaDB> SHOW VARIABLES WHERE Variable_name='autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+

As I read on document, when autocommit is on, you cannot rollback transaction as stated here 正如我在文档中读到的那样,当autocommit打开时,您无法回滚此处所述的事务

By default, MySQL runs with autocommit mode enabled. 默认情况下,MySQL在启用自动提交模式的情况下运行。 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. 这意味着只要执行更新(修改)表的语句,MySQL就会将更新存储在磁盘上以使其永久化。 The change cannot be rolled back. 无法回滚更改。

So I write a little script for testing. 所以我写了一个小脚本进行测试。 Firstly, I start a transaction and update some data: 首先,我启动一个事务并更新一些数据:

BEGIN;
UPDATE foo SET year = 2019  WHERE id = 1;
Query OK, 1 row affected (0.000 sec)
Rows matched: 1  Changed: 1  Warnings: 0

So It looks like I have done. 所以看起来我已经完成了。 Then I rollback: 然后我回滚:

ROLLBACK;
Query OK, 0 rows affected (0.005 sec)

Then I check again updated record, I see that data is not change. 然后我再次检查更新记录,我看到数据没有变化。 It's weird, because I think data will always change no matter what because autocommit flag is on. 这很奇怪,因为我认为数据总是会因为autocommit标志打开而改变。

Please explain for me why. 请解释一下为什么。 Thanks 谢谢

BEGIN is an explicit start of transaction that disables the effect of autocommit . BEGIN是一个明确的事务开始,它禁用了autocommit的效果。

Autocommit applies to SQL that isn't explicitly transactional. 自动提交适用于非显式事务性的SQL。

Even if autocommit is on, if you use BEGIN or START TRANSACTION , it temporarily suspends the autocommit of each statement until you finish the transaction. 即使启用了autocommit ,如果您使用BEGINSTART TRANSACTION ,它会暂时挂起每个语句的自动提交,直到您完成事务。

You cited the manual page https://dev.mysql.com/doc/refman/8.0/en/commit.html , which goes on to explain: 您引用了手册页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: 要为一系列语句隐式禁用自动提交模式,请使用START TRANSACTION语句:

With START TRANSACTION, autocommit remains disabled until you end the transaction with COMMIT or ROLLBACK. 使用START TRANSACTION时,自动提交将保持禁用状态,直到您使用COMMIT或ROLLBACK结束事务。 The autocommit mode then reverts to its previous state. 然后,自动提交模式将恢复为先前的状态。

(emphasis mine) (强调我的)

In other words, the statements you execute after BEGIN or START TRANSACTION are not committed automatically. 换句话说,您在BEGINSTART TRANSACTION之后执行的语句不会自动提交。 This is expected. 这是预料之中的。

While the previous Answers are correct, let me point out another angle. 虽然之前的答案是正确的,但让我指出另一个角度。

If you run a billion-row UPDATE (which will take hours), and pull the plug on the computer, the UPDATE will be partially finished. 如果您运行十亿行UPDATE (这将需要数小时),并拔下计算机上的插头, UPDATE将部分完成。 Upon restarting the computer (and MySQL), what happens? 重启计算机(和MySQL)后会发生什么? In MyISAM, some rows would be updated, some would not. 在MyISAM中,某些行会更新,有些则不会。 But with InnoDB, it will ROLLBACK the partially finished UPDATE (and may take some more hours to do so). 但是使用InnoDB,它将ROLLBACK部分完成UPDATE (并且可能需要更长时间才能完成)。

So, the quote from the manual was not only ambiguous (as pointed out by the other Answers), but it was 'literally' incorrect. 因此,手册中的引用不仅含糊不清(正如其他答案所指出的那样),但它“确实”不正确。 In my example, the change can and was rolled back. 在我的示例中,更改可以并且回滚。

I like to phrase it thus: 我喜欢这样说:

Autocommit=ON , when not otherwise in a transaction, is equivalent to wrapping the statement in BEGIN and COMMIT . Autocommit=ON ,否则在事务中,否则相当于将语句包装在BEGINCOMMIT That is, the statement is performed atomically. 也就是说,语句是以原子方式执行的。

I filed http://bugs.mysql.com/95414 . 我提交了http://bugs.mysql.com/95414

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM