【Mysql】mysql查询超时JDBC源码浅析

前言

    本文讨论的源码是基于connectorJ 5.1.37,最新版的jar包是5.1.38,两者对于该处的逻辑并无差别。

    connectorJ MySQL官网下载地址:点击打开链接(http://dev.mysql.com/downloads/connector/j/)


一、JDBC API支持

    Java.sql.Statement中定义的查询超时规范:

[html]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. /**  
  2.      * Sets the number of seconds the driver will wait for a  
  3.      * <code>Statement</code> object to execute to the given number of seconds.  
  4.      *By default there is no limit on the amount of time allowed for a running  
  5.      * statement to complete. If the limit is exceeded, an  
  6.      * <code>SQLTimeoutException</code> is thrown.  
  7.      * A JDBC driver must apply this limit to the <code>execute</code>,  
  8.      * <code>executeQuery</code> and <code>executeUpdate</code> methods.  
  9.      * <p>  
  10.      * <strong>Note:</strong> JDBC driver implementations may also apply this  
  11.      * limit to {@code ResultSet} methods  
  12.      * (consult your driver vendor documentation for details).  
  13.      * <p>  
  14.      * <strong>Note:</strong> In the case of {@code Statement} batching, it is  
  15.      * implementation defined as to whether the time-out is applied to  
  16.      * individual SQL commands added via the {@code addBatch} method or to  
  17.      * the entire batch of SQL commands invoked by the {@code executeBatch}  
  18.      * method (consult your driver vendor documentation for details).  
  19.      *  
  20.      * @param seconds the new query timeout limit in seconds; zero means  
  21.      *        there is no limit  
  22.      * @exception SQLException if a database access error occurs,  
  23.      * this method is called on a closed <code>Statement</code>  
  24.      *            or the condition {@code seconds >= 0} is not satisfied  
  25.      * @see #getQueryTimeout  
  26.      */  
  27.     void setQueryTimeout(int seconds) throws SQLException;  

    JDBC规范中的执行对象关系——CallableStatement extends PreparedStatement extends Statement,因此setQueryTimeout均可以支持。


二、JDBC实现源码浅析

    要追查询超时的源码逻辑,入口显然是statement.executeQuery。本文关注查询超时在mysql中实现的逻辑,其他无关的源码在此不做分析。有关超时的逻辑,实际上是在executeQuery中启动了一个timer定时器,超时则向mysql服务器发送“kill query”指令,整个逻辑非常简单。其中需要关注两个点:一个是timer的run逻辑,另一个是mysql对于kill query语法的支持逻辑。

    在statement.executeQuery方法的实现中开启了一定时器,在指定时间之后运行CancelTask(CancelTask immplments Runnable),超时处理的逻辑都被封装到了CancelTask的run方法中。

    而在CancelTask的run方法中则启动了一个线程,该线程会在超时以后向mysql服务器发送“Kill QUERY thread_id”指令,这个指令正式JDBC操作和mysql服务器之间进行RPC的关键。mysql服务器是否支持JDBC查询超时规范的操作,关键在于对“KILL QUERY”的语义和支持。
    最后一个需要关注的实现是逻辑是,如果查询操作没有超时,此时应该取消掉CancelTask任务的执行,在JDBC Mysql实现的源码中,其逻辑为执行execSQL获得结果集后立即调用CancelTask.cancel()来改变任务状态,逻辑简单,再次不在赘述,简单贴出源码。


三、Mysql对超时的支持

    整个JDBC规范及其实现中,将java与mysql联系到一起的是connection对象,实际上jdbc操作也是一种RPC,java应用远程调用mysql应用,通过jdbc协议进行通信。而JDBC协议(jdbc:mysql://xxxx/3306/database,主协议是jdbc,副协议是mysql)基于socket,在connection.connect(url, properties)的逻辑中通过反射connection实现类的构造函数实例化MysqlIO对象,此时会进行socket通信和握手协议,失败则JDBC异常。

    扯远了,回到Mysql对超时的技术支持。

    参见mysql官方文档中关于kill query的内容:13.7.6.3 KILL Syntax

    对应的中文翻译:点击打开链接

    其中关注两个点,指令语法和指令含义。

1. 语法

[html]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. KILL [CONNECTION | QUERY] thread_id  

2. 含义

[html]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. KILL QUERY terminates the statement the connection is currently executing, but leaves the connection itself intact.  
  2. KILL QUERY会终止连接当前正在执行的语句,但是会保持连接的原状。  

3. 注意

    需要注意的是,KILL QUERY指令并不会关闭当前连接,而只是结束当前连接的操作,否则连接池在超时机制下就没什意义了。


四、总结

    JDBC中查询超时的逻辑:

    1. 在进行查询操作的时候启动定时器,超时则调用CancelTask;

    2. 在CancelTask中,java应用通过jdbc协议对mysql服务器进行RPC,调用mysql “KILL QUERY”指令结束当前连接执行的操作;

    3. 如果在执行完query操作还没有超时,则取消CancelTask,否则CancelTask在超时后RPC “KILL QUERY";


附注:

    本文写的过于简单,乘中午休息时间不睡觉匆忙写了写,有些地方不详细,如有错漏,还请不吝指正,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值