我有一个基于Web的数据服务的MySQL连接池。当它开始为请求提供服务时,它需要从池中连接才能使用。问题是如果自从使用该特定连接以来已经存在显着的暂停,则服务器可能已经将其计时并且关闭其结束。我希望能够在池管理代码中检测到这一点。
诀窍是:我编码的环境只给我一个非常抽象的API连接。我基本上只能执行SQL语句。我无权访问实际套接字或直接访问MySQL客户端API。
所以,问题是:我可以在连接上执行的最便宜的MySQL语句是什么,以确定它是否正常工作。例如SELECT 1;
应该可以工作,但我想知道是否有更便宜的东西?也许某些东西甚至没有通过电子邮件,但是在MySQL客户端库中处理并有效地回答了同样的问题?
澄清:我不关心检查MySQL服务器是否正在运行,或者它的数据库配置是否足以回答查询。如果这些事情发生故障,那么服务执行的后续SQL将获取并处理相应的错误。我真的只关心TCP连接是否打开...因为如果服务器关闭它,那么Web服务的SQL将收到一个错误,意味着“只需重新连接并再试一次”,这样就不方便了。服务代码的渣土。
关闭: /* ping */
hack正是我想要的那种,但唉只能通过JDBC获得。通过文档阅读该hack,很明显它被放在那里完全与我想要的原因相同。好奇的是,我使用Haskel和HDBC在HDBC-mysql工作。我将要求HDBC-mysql的作者添加一种方法来直接或通过类似的黑客调用mysql_ping()
。
Vlad的DO 1
也是我追求的那种东西,而且由于另一种hack在JDBC之外是不可用的,我将使用它。
感谢所有精彩的讨论,特别是@Vlad!
答案 0 :(得分:13)
你在没有通过电话的情况下不会知道连接的真实状态,并且SELECT 1
是一个足够好的候选人(可以说你可以提出一个更短的命令是时候解析,但与网络甚至环回延迟相比,这些节省是微不足道的。)
话虽如此,我认为在从池中检出连接之前ping 并不是最好的方法。
您可能只是让您的连接池管理器强制执行其自己的保持活动(超时)策略,以避免被服务器断开连接(没有更严重的干预连接问题,这可能会影响您无论如何,在常规操作的中间 - 你的连接池管理器无论如何都无法帮助),以及为了不占用数据库(想想文件句柄和内存使用)不必要
因此,在我看来,在检查来自池的连接之前确定连接条件的价值是值得怀疑的。在将连接重新检入池中之前,可能需要测试连接状态 ,但是当出现SQL硬错误(或等效异常)时,只需将连接标记为脏即可隐式执行此操作(除非您使用的API已经公开is-bad
- 就像您的呼叫一样。)
因此我建议:
从您的评论中可以看出,您确实确实想要ping连接(我认为这是因为您无法完全控制或了解MySQL服务器上的超时特性或干预网络设备,如代理等。)
在这种情况下,您可以使用DO 1
替代SELECT 1
;它略微更快 - 解析时更短,并且它不会返回实际数据(尽管 将获得TCP ack
,所以你仍然会这样做验证连接仍然建立的往返。)
关于Joshua's post,这里是各种场景的数据包捕获跟踪:
SELECT 1;
13:51:01.463112 IP client.45893 > server.mysql: P 2270604498:2270604511(13) ack 2531191393 win 1460 <nop,nop,timestamp 2983462950 59680547>
13:51:01.463682 IP server.mysql > client.45893: P 1:57(56) ack 13 win 65306 <nop,nop,timestamp 59680938 2983462950>
13:51:01.463698 IP client.45893 > server.mysql: . ack 57 win 1460 <nop,nop,timestamp 2983462951 59680938>
DO 1;
13:51:27.415520 IP client.45893 > server.mysql: P 13:22(9) ack 57 win 1460 <nop,nop,timestamp 2983488906 59680938>
13:51:27.415931 IP server.mysql > client.45893: P 57:68(11) ack 22 win 65297 <nop,nop,timestamp 59681197 2983488906>
13:51:27.415948 IP client.45893 > server.mysql: . ack 68 win 1460 <nop,nop,timestamp 2983488907 59681197>
mysql_ping
14:54:05.545860 IP client.46156 > server.mysql: P 69:74(5) ack 78 win 1460 <nop,nop,timestamp 2987247459 59718745>
14:54:05.546076 IP server.mysql > client.46156: P 78:89(11) ack 74 win 65462 <nop,nop,timestamp 59718776 2987247459>
14:54:05.546092 IP client.46156 > server.mysql: . ack 89 win 1460 <nop,nop,timestamp 2987247459 59718776>
正如您所看到的,除了mysql_ping
数据包是5个字节而不是DO 1;
的9个字节这一事实之外,往返次数(以及因此网络引发的延迟)正是如此相同。使用DO 1
而不是mysql_ping
支付的唯一额外费用是DO 1
的解析,这是微不足道的。
答案 1 :(得分:6)
我不确定您当前正在使用哪种API(或使用什么语言),但对于Java,JDBC驱动程序可以执行一项特殊操作。
标准测试查询是:
select 1
正如你所指出的那样。如果您将其修改为:
/* ping */ select 1
JDBC驱动程序会注意到这一点,并且只向MySQL服务器发送一个数据包以获得响应。
我在题为MySQL Tips for Java Developers With Mark Matthews的太阳'深潜'一集中了解到这一点。
即使你没有使用Java,也许在其他mysql驱动程序中实现了同样的技巧?我假设服务器需要知道这个特殊的数据包,所以它可以发送响应......
答案 2 :(得分:1)
这种情况下的“连接”有多种含义。 MySQL侦听套接字 - 这是网络级别的“连接”。 MySQL维护“数据库连接”,其中包括查询执行和其他开销的上下文。
如果您只想知道服务是否正在侦听,您应该能够执行网络级调用,以查看端口(不知道默认值是什么)是否正在侦听目标IP。如果你想让MySQL引擎做出响应,我认为你的SELECT 1
想法是好的 - 它实际上并没有从数据库中获取任何数据,而是确认引擎已经启动并响应。