打开两个mysql
命令行客户端并连接到您的数据库。在客户端 #1 中,输入
START TRANSACTION;
Run Code Online (Sandbox Code Playgroud)
在客户端 #2 中,使用SHOW PROCESSLIST
,然后
KILL [n];
Run Code Online (Sandbox Code Playgroud)
n
客户端 #1 连接的 ID在哪里。Bam——事务回滚。但是客户#1 不知道这一点。然后从客户端#1,发送一些命令——比如说,
UPDATE clients SET important_field = NULL;
Run Code Online (Sandbox Code Playgroud)
你会得到这样的回应:
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Query OK, 10000 rows affected (0.05 sec)
Rows matched: 10000 Changed: 10000 Warnings: 0
Run Code Online (Sandbox Code Playgroud)
哎呀,你说,更好地击中ROLLBACK!
然后你意识到,令你恐惧的是,你不再参与交易了。
这是我的问题:如果我想KILL
在某个时候建立连接,有什么方法可以确保这种“现在你在一个事务中,现在你不在”的情况不会发生,除了将autocommit设置为0 系统级?
请注意,以上内容是在mysql
5.1下测试的- 如果更高版本提供修复,我很想听听。我也很想看到用 JDBC、ADO.NET 等完成的测试,看看它们是否容易受到同样的问题的影响。
(在元注释上,这个问题来自 Server Fault 上的两个问题。我真的希望 DBA 社区能够提供更多帮助......)
更新:请参阅下面的我的答案。这个问题似乎是mysql
命令行实用程序所独有的,它具有奇怪的自动重新连接“功能”。最有可能的是,任何不是建立在mysql
实用程序之上的工具或库都不会表现出这种行为。但是,您可能想要测试您正在使用的任何内容以确保安全,或者接受 drachenstern 的建议并将您的事务包装在存储过程中。
这两个问题的答案有什么问题?他们是 100% 准确的,所以我不确定我们还能做些什么来帮助你。
我建议你确认你永远不要假设你在进行交易。始终检查以确保您是。在 TSQL 中,它就像检查 @@TRANCOUNT 是否大于 0 一样简单。这与您想要检查互斥锁的任何线程情况相同。如果你用存储过程来做会发生什么?它会杀死存储过程,是吗?因为 SP 旨在是原子的。你所展示的与原子性无关。
需要明确的是,这种行为是设计使然!不要在控制台中手动运行原子事务,将它们放在程序中,这样如果连接消失,它就会消失。这不是你可以“只是希望工作正常”的东西。
如果你有东西必须是ACID,你必须把它放在一个可以做成ACID的容器里。这意味着存储过程等。
事实证明,有一个比我之前建议的更简单的答案:启动mysql
客户端时,使用该--disable-reconnect
标志。
最初的问题源于mysql
命令行客户端奇怪的默认行为,即如果连接丢失,无论潜在的危害有多大,都会自动重新连接并发送给定的命令。对于--disable-reconnect
,以下是它被杀死并发送查询后发生的情况:
UPDATE clients SET important_field = NULL;
Run Code Online (Sandbox Code Playgroud)
响应是
ERROR 2006 (HY000): MySQL server has gone away
Run Code Online (Sandbox Code Playgroud)
并且查询没有通过。进一步的查询也会产生相同的错误,直到我手动重新连接。
mysql
因此,如果您在一个重要的数据库上使用命令行客户端工作,我建议使用--disable-reconnect
默认值。
这也有助于减轻我对 Java、Ruby 等中的绑定的担忧;虽然我当然建议测试您使用的任何特定绑定,但似乎任何流行的 MySQL 库都不太可能使用“自动重新连接和重新发送”行为。但是,编码人员必须小心,他们的程序没有任何可能无意中执行此操作的函数(例如,在引发异常后重试单个查询,而不是重新启动整个事务)。
归档时间: |
|
查看次数: |
1678 次 |
最近记录: |