从MySQL docs我得到以下内容(错误代码):
1205(ER_LOCK_WAIT_TIMEOUT)
锁定等待超时已过期。等待太久的陈述是 回滚(不是整个交易)。你可以增加价值 如果是SQL语句,则为innodb_lock_wait_timeout配置选项 应该等待更长时间才能完成其他交易,或者减少它 如果太长时间运行的事务导致锁定问题和 减少繁忙系统的并发性。
在本声明中,它明确区分了语句回滚和事务回滚。我的问题是如何回滚一个语句,并且运行中的事务不会回滚?更重要的是,我在事务中获得了这样的锁定超时,并且回滚了完整的事务。有人可以启发我吗?
答案 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事务已提交) )