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


我需要让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的事务。


1898
2018-03-30 03:40


起源

有趣的问题。我以为这是自动的!所以我们需要类似的东西 innodb_rollback_on_disconnect..那将是伟大的,我会说,这应该是默认的!这对mysql来说是合理的变更请求。 - TMS


答案:


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

无论如何。您可以更改两个变量。他们基本上做同样的事情,但对不同的客户。

首先是 WAIT_TIMEOUT 它被java或php等应用程序客户端使用。

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

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


10
2018-04-08 05:57



感谢您的回复,我尝试使用这两个选项,并将它们设置为60秒(用于实验),但又出现了另一个问题。在60秒不活动(空闲)后,连接自动关闭,下一个查询产生错误(服务器已经消失),然后自动重新连接。我需要编码一些东西来查询每59秒以确保连接活着吗?或者还有另一种方式吗?超过60秒的长查询是否会在进程中间断开连接? - qsoft
因为我在事务中只需要这种行为,我可以做类似的事情 SET SESSION wait_timeout = 60 就在事务之前,在提交/回滚后恢复它? - qsoft
在开始事务之前,您应该能够在存储过程中更改它或作为单独的语句更改它。你关于空闲连接被关闭是正确的。这就是它的工作原理。但是,就我所见,长时间运行的查询并不算“闲置”,因此应该是安全的(易于测试) select 1, sleep(61) from dual) - Andreas Wederbrand
哇谢谢,所以我就开始了 SET @old_wait_timeout := @@session.wait_timeout; SET @@session.wait_timeout := 60; 就在此之前 START TRANSACTION; 然后在a之后恢复它 COMMIT 要么 ROLLBACK 运用 SET @@session.wait_timeout := @old_wait_timeout;。我希望这有效 - qsoft
@qsoft我的理解:wait_timeout是一个非活动超时。意味着它将被清除并在每次激活后重新启动,例如:表扫描,行插入,接收的网络包等。因此,在事务下,我们可以将此选项设置为较小的值(例如:5秒)。这将更适合于错误检测和故障恢复。 - ASBai