具有丢失/断开连接的事务上的MySQL回滚

时间:2012-03-30 03:40:35

标签: mysql transactions timeout rollback disconnect

我需要让MySQL服务器在客户端断开连接后立即回滚事务,因为每个客户端同时工作。问题可以像这样再现(使用innodb表类型)

在客户A上:

START TRANSACTION;
SELECT MAX(ID) FROM tblone FOR UPDATE;
#... then disconnect your connection to the server

在客户B上:

START TRANSACTION;
SELECT MAX(ID) FROM tblone FOR UPDATE;
#... lock wait time out will occur here

我设置了MySQL的服务器选项,如innodb_rollback_on_timeout,并在两个客户端上使用mysql的客户端mysql --skip-reconnect。我在网络上尝试使用一台服务器和两台客户端。我在SELECT ... FOR UPDATE;行之后物理断开了网络连接(拔掉电缆)。我需要让其他客户端能够立即在事务上使用tblone(锁定它,更新它),为此,我认为服务器应该在客户端A断开连接后回滚客户端A的事务。

2 个答案:

答案 0 :(得分:12)

当您在物理上断开客户端连接时,您没有发送正常断开连接(这会导致回滚)并且MySQL协议不是很繁琐,因此服务器永远不会知道客户端不存在。我认为,与客户端和服务器内部会话的其他数据库系统进行比较时,这是协议中的一个缺陷。

反正。您可以更改两个变量。他们基本上做同样的事情,但针对不同的客户。

第一个是wait_timeout,它由java或php等应用程序客户端使用。

另一个是interactive_timeout,它由mysql客户端使用(如在测试中)

在这两种情况下,服务器会在几秒钟后终止连接,这样做会回滚所有事务并释放所有锁。

答案 1 :(得分:1)

这是为了讨论一些评论。请注意,这与某些评论不一致。我将使用 INSERT 而不是 SELECT..FOR UPDATE 因为效果更明显。

让我们看一些不同的情况:

(1) 无 SQL + 超时

commitConfiguration

避免这种情况,因为下面详述的情况。解决方案:不要依赖 InnoDB 来帮助您处理长事务。

(2) 长时间运行的查询

START TRANSACTION;
do some SQL statement(s)
do no SQL for more than the timeout (before COMMITing)

一切都很好。只要服务器 (mysqld) 继续执行查询,超时就不适用。也就是说,超时“时钟”在每个 SQL 语句结束时重新开始

(3)(自动重新连接)

START TRANSACTION;
do some SQL statement(s)
run an SQL query that takes more than the timeout
COMMIT;

123 会回滚; 456 将被插入。 (同样 SELECT..FOR UPDATE 会失去锁。)不好。解决方案是关闭“自动重新连接”。相反,检查错误并将断开连接错误视为事务的致命错误。 (然后重新开始交易。)

INSERT 456 将在由 START TRANSACTION; INSERT ... VALUES (123); time passes; no SQL performed for longer than the timeout disconnect occurs INSERT ... VALUES (456); auto-reconnect (because you have it ENabled); the INSERT proceeds COMMIT; 控制的新事务中运行。

(4)(没有自动重新连接)

autocommit

123 将被回滚。 456 的 INSERT 将得到类似“连接丢失”的错误。重新开始交易。