mysql jdbc timer_Mysql JDBC-mysql-Driver queryTimeout分析

Mysql jdbc的queryTimeout分析

Mysql的jdbc-driver

com.mysql.jdbc.Driver

设置queryTimeout方法

com.mysql.jdbc.StatementImpl.setQueryTimeout

StatementImpl实例有一个field:timeoutInMillis

public void setQueryTimeout(int seconds) throws SQLException {

synchronized(this.checkClosed().getConnectionMutex()) {

if(seconds < 0) {

throw SQLError.createSQLException(Messages.getString("Statement.21"), "S1009", this.getExceptionInterceptor());

} else {

this.timeoutInMillis = seconds * 1000;

}

}

}

queryTimeout使用场景示例:

com.mysql.jdbc.StatementImpl.executeQuery

ResultSet executeQuery(String sql) throws SQLException;

executeQuery有一个较复杂的逻辑:

获取connection的互斥锁

校验、初始化一些配置,是否为ping请求

sql转义,防sql注入

判断timeout是否有效,有效时创建一个CancelTask

将cancelTask放入Timer中延迟执行

locallyScopedConn.getCancelTimer().schedule(timeoutTask, (long)this.timeoutInMillis);

也就是在当前时间的timeoutInMillis后会执行这个Task

执行sql语句,获取结果

超时任务判断,如果有超时任务,分为两种情况:1 超时异常已经抛出,直接返回异常;1 超时任务未执行,cancel超时任务

this.results = locallyScopedConn.execSQL(this, sql, this.maxRows, (Buffer)null, this.resultSetType, this.resultSetConcurrency, this.createStreamingResultSet(), this.currentCatalog, cachedFields);

if(timeoutTask != null) {

if(timeoutTask.caughtWhileCancelling != null) {

throw timeoutTask.caughtWhileCancelling;

}

timeoutTask.cancel();

locallyScopedConn.getCancelTimer().purge();

timeoutTask = null;

}

获取lastInsertId

返回results

StatementImpl.CancelTask

class CancelTask extends TimerTask {

SQLException caughtWhileCancelling = null;

StatementImpl toCancel;

Properties origConnProps = null;

String origConnURL = "";

long origConnId = 0L;

CancelTask(StatementImpl cancellee) throws SQLException {

this.toCancel = cancellee;

this.origConnProps = new Properties();

Properties props = StatementImpl.this.connection.getProperties();

Enumeration keys = props.propertyNames();

while(keys.hasMoreElements()) {

String key = keys.nextElement().toString();

this.origConnProps.setProperty(key, props.getProperty(key));

}

this.origConnURL = StatementImpl.this.connection.getURL();

this.origConnId = StatementImpl.this.connection.getId();

}

public void run() {

Thread cancelThread = new Thread() {

public void run() {

Connection cancelConn = null;

java.sql.Statement cancelStmt = null;

try {

MySQLConnection npe = (MySQLConnection)StatementImpl.this.physicalConnection.get();

if(npe != null) {

if(npe.getQueryTimeoutKillsConnection()) {

CancelTask.this.toCancel.wasCancelled = true;

CancelTask.this.toCancel.wasCancelledByTimeout = true;

npe.realClose(false, false, true, new MySQLStatementCancelledException(Messages.getString("Statement.ConnectionKilledDueToTimeout")));

} else {

Object var4 = StatementImpl.this.cancelTimeoutMutex;

synchronized(StatementImpl.this.cancelTimeoutMutex) {

if(CancelTask.this.origConnURL.equals(npe.getURL())) {

cancelConn = npe.duplicate();

cancelStmt = cancelConn.createStatement();

cancelStmt.execute("KILL QUERY " + npe.getId());

} else {

try {

cancelConn = (Connection)DriverManager.getConnection(CancelTask.this.origConnURL, CancelTask.this.origConnProps);

cancelStmt = cancelConn.createStatement();

cancelStmt.execute("KILL QUERY " + CancelTask.this.origConnId);

} catch (NullPointerException var25) {

;

}

}

CancelTask.this.toCancel.wasCancelled = true;

CancelTask.this.toCancel.wasCancelledByTimeout = true;

}

}

}

} catch (SQLException var27) {

CancelTask.this.caughtWhileCancelling = var27;

} catch (NullPointerException var28) {

;

} finally {

if(cancelStmt != null) {

try {

cancelStmt.close();

} catch (SQLException var24) {

throw new RuntimeException(var24.toString());

}

}

if(cancelConn != null) {

try {

cancelConn.close();

} catch (SQLException var23) {

throw new RuntimeException(var23.toString());

}

}

CancelTask.this.toCancel = null;

CancelTask.this.origConnProps = null;

CancelTask.this.origConnURL = null;

}

}

};

cancelThread.start();

}

}

timeout后执行的操作主要为:

cancelConn = npe.duplicate(); //复制一个当前连接配置相同的连接

cancelStmt = cancelConn.createStatement(); //创建一个Statement对象,用来发送sql语句到数据库

cancelStmt.execute("KILL QUERY " + npe.getId()); //杀掉已经timeout的语句

可以看到,只要CancelTask执行,除了执行sql的连接压根没有成功生成外,都会执行KILL QUERY操作,里面不做任何请求是否已成功的判断。

原因也比较明显,凡是执行到CancelTask,说明确实超时了。

原文:https://www.cnblogs.com/windliu/p/9830508.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值