我需要让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的事务。
答案 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 将得到类似“连接丢失”的错误。重新开始交易。