最便宜的方法来确定MySQL连接是否仍然存在

Mtn*_*ark 13 mysql libmysql hdbc

我有一个基于Web的数据服务的MySQL连接池.当它开始为请求提供服务时,它需要从池中连接才能使用.问题是如果自从使用该特定连接以来已经存在显着的暂停,则服务器可能已经将其计时并且关闭其结束.我希望能够在池管理代码中检测到这一点.

诀窍是:我编码的环境只给我一个非常抽象的API连接.我基本上只能执行SQL语句.我无权访问实际的套接字或直接访问MySQL客户端API.

所以,问题是:我可以在连接上执行哪个最便宜的MySQL语句,以确定它是否正常工作.比如SELECT 1;应该工作,但我想知道是否有更便宜的东西?也许某些东西甚至没有通过网络,但在MySQL客户端库中处理并有效地回答相同的问题?

澄清:我不关心检查MySQL服务器是否正在运行,或者它的数据库配置是否足以回答查询.如果这些事情发生故障,那么服务执行的后续SQL将获取并处理相应的错误.我真的只关心TCP连接是否打开...因为如果服务器关闭它,那么Web服务的SQL将收到一个错误,意味着"只需重新连接并再试一次",这样就不方便了.服务代码的渣土.

关闭:/* ping */黑客正是那种我一直在寻找的东西,但可惜只能通过JDBC.通过文档阅读该hack,很明显它被放在那里的原因与我想要的完全相同.对于好奇,我在Haskel工作,使用HDBCHDBC-mysql.我将要求HDBC-mysql的作者添加一种mysql_ping()直接或通过类似黑客调用的方法.

Vlad's DO 1也是我追求的那种东西,而且由于另一个hack在JDBC之外是不可用的,我将使用它.

感谢所有精彩的讨论,特别是@Vlad!

vla*_*adr 14

不会知道连接的真实状态,并且SELECT 1是一个足够好的候选者(可以说你可以提出一个更短的命令,花费更少的时间来解析,但与网络或甚至环回延迟相比,这些节省会无足轻重.)

话虽如此,我认为从池中检出连接之前 ping一个连接并不是最好的方法.

您可能只是让您的连接池管理器强制执行其自己的保持活动(超时)策略,以避免被服务器断开连接(缺少更严重的干预连接问题,这可能会影响您在常规操作的中间 - 无论如何 -并且你的连接池管理器无论如何都无法提供帮助),以及为了不用不必要地占用数据库(想想文件句柄和内存使用).

因此,在我看来,在检查来自池的连接之前对连接条件进行什么样的值测试是值得怀疑的.在将连接重新检入池之前测试连接状态可能是值得,但是当出现SQL硬错误(或等效异常)时,可以通过简单地将连接标记为脏来隐式地完成(除非您已经使用的API)is-bad为你公开一个类似的电话.)

因此我建议:

  • 实施客户端保持活力政策
  • 检查池中的连接时不执行任何检查
  • 在将连接返回到池之前执行脏检查
  • 让应用程序代码处理其他(非超时)异常连接条件

UPDATE

这样看来,从你的意见,你真的真的要ping的连接(我认为那是因为你没有或完全控制,或知识,MySQL服务器上超时特性干预网络设备,如代理等)

在这种情况下,你可以使用DO 1作为替代SELECT 1; 它稍微快一点 - 解析时间更短,并且它不会返回实际数据(尽管您获得TCP ack,因此您仍将进行往返验证,即连接仍然已建立.)

更新2

关于Joshua的帖子,这里有各种场景的数据包捕获跟踪:

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>
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,除了mysql_ping数据包是5个字节而不是DO 1;9个字节这一事实之外,往返次数(以及因此网络引发的延迟)完全相同.您正在使用支付唯一的额外成本DO 1,而不是mysql_ping是的解析DO 1,这是微不足道的.


Jos*_*non 6

我不确定您当前使用的是什么API(或使用什么语言),但对于Java,JDBC驱动程序可以执行一项特殊操作.

标准测试查询是:

select 1
Run Code Online (Sandbox Code Playgroud)

正如你所指出的那样.如果您将其修改为:

/* ping */ select 1
Run Code Online (Sandbox Code Playgroud)

JDBC驱动程序会注意到这一点,并只向MySQL服务器发送一个数据包以获得响应.

我在Sun的"Deep Dive"剧集中了解到了这一点,题为" Java开发者的MySQL技巧"和Mark Matthews.

即使你没有使用Java,也许在其他mysql驱动程序中实现了同样的技巧?我假设服务器需要知道这个特殊的数据包,所以它可以发送响应...