MySQL中的语句回滚与事务回滚

时间:2016-01-21 12:57:27

标签: mysql transactions locking

MySQL docs我得到以下内容(错误代码):

  •   

    1205(ER_LOCK_WAIT_TIMEOUT)

         

    锁定等待超时已过期。等待太久的陈述是   回滚(不是整个交易)。你可以增加价值   如果是SQL语句,则为innodb_lock_wait_timeout配置选项   应该等待更长时间才能完成其他交易,或者减少它   如果太长时间运行的事务导致锁定问题和   减少繁忙系统的并发性。

在本声明中,它明确区分了语句回滚和事务回滚。我的问题是如何回滚一个语句,并且运行中的事务不会回滚?更重要的是,我在事务中获得了这样的锁定超时,并且回滚了完整的事务。有人可以启发我吗?

2 个答案:

答案 0 :(得分:2)

与事务类似,语句也是原子的。一旦语句开始执行数据更改,就会保存原始状态(实际上会记录更改)。如果语句因任何原因失败(超时,与刚刚提交的事务冲突),则必须将更改还原为原始状态。该语句将报告失败但事务仍处于打开状态,您可以继续执行该事务,就像该语句从未执行过一样。

这实际上类似于保存点 - 您可以想象在记录每个语句保存点之前和语句完成之后,保存点已提交。但这对外部交易或保存点没有影响。

答案 1 :(得分:0)

接受的答案是完全正确的,但是我最终还是在同一文档页面上,进行了快速测试设置,并且由于注释太短,如果您愿意自己进行测试并查看行为,则可以使用以下设置:

1)初始化表

CREATE TABLE `x` (
    `id` INT(10) UNSIGNED NOT NULL,
    `xx` INT(11) NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
)
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
;
INSERT INTO X (id, xx) VALUES (1,NULL),(2,NULL),(3,NULL);

2)打开客户端连接,启动事务,触发INSERT以将行锁定在新创建的表中

START TRANSACTION;
INSERT INTO X (id, xx) VALUES (1, 5) ON DUPLICATE KEY UPDATE xx = VALUES(xx);

不提交交易

3)打开一个 second 客户端连接,开始一个事务,然后在非锁定行上触发另一个INSERT

START TRANSACTION;
INSERT INTO X (id, xx) VALUES (2, 7) ON DUPLICATE KEY UPDATE xx = VALUES(xx);

再次,不要提交。

到目前为止,如果发出SELECT * FROM x,则客户端1看到“ 1,5; 2,NULL,3; NULL”,而客户端2看到“ 1,NULL; 2,7; 3,NULL”

4)在客户端2上触发锁定的INSERT,然后等待其死于SQL 1025:

INSERT INTO X (id, xx) VALUES (1, 6) ON DUPLICATE KEY UPDATE xx = VALUES(xx);

现在,如果在客户端2上发布SELECT * FROM x,我们仍然会看到“ 1,NULL; 2,7; 3,NULL”,因此声明被回滚了。如果我们在客户端1上发布它,我们还将仍然看到“ 1,5; 2,NULL; 3,NULL”,因此客户端2事务仍在运行(假定您的客户端未配置为在每个SQL错误时自动回滚)。 / p>

5)现在,如果您在两个客户端上均发出ROLLBACK,则该表将“恢复”为所有NULL值。如果您COMMIT,则会得到“ 1,5; 2,7,3,NULL”(“ 1,6”在回滚时无处可寻,但客户端2事务已提交) )