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中延迟执行
if (locallyScopedConn.getEnableQueryTimeouts() && this.timeoutInMillis != 0 && locallyScopedConn.versionMeetsMinimum(5, 0, 0)) {
timeoutTask = new CancelTask(this);
//每个连接会有一个CancelTimer,一个deamon线程
locallyScopedConn.getCancelTimer().schedule(timeoutTask, 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,说明确实超时了。
connectTimeout=5000&socketTimeout=10000
其实,设置了queryTimeout也不一定生效,上述代码中无论是成功执行,还是CancelTask,都会涉及到对socket的操作,socket操作是底层的,它也有timeout选项,错误的配置或不配置,会采用操作系统的默认配置,这个时间可能是长达30分钟的。一旦网络出现问题,调用socket.read()时阻塞了,都到导致应用程序假死。
解决办法
在jdbc.url中配置参数connectTimeout和socketTimeout参数,当然他们的值应该大于计划内的程序执行sql的最长耗时时间,否则可能中断正常的sql执行。
Mysql JDBC-mysql-Driver queryTimeout分析的更多相关文章
- 数据库 MySQL Jdbc JDBC的六个固定步骤
*0 案例: a)在JavaScript中使用正则表达式,在JS中正则表达式的定界符是:// var regexp = /^[0-9]+$/; if(regexp.test(nu ...
- JDBC MYSQL 学习笔记(一) JDBC 基本使用
1.JDBC简单介绍 SUN公司为了简化.统一对数据库的操作,定义了一套Java操作数据库的规范.称之为JDBC. JDBC全称为:Java Data Base Connectivity(java数据 ...
- 无法找到类:java.lang.ClassNotFoundException: com.mysql.jdbc.driver
转载自:http://blog.csdn.net/huangbiao86/article/details/6428608 问题描述:连接数据库,而明明已经将mysql-connector-java-5 ...
- MySQL JDBC的queryTimeout坑
遇到一个MySQL JDBC跑execute规定的方法queryTimeout坑,更恶心,无论是BUG,不能,^_^,为什么要说?请看下面的说明: 现象: 用同一个Connection运行大批量SQL ...
- Spring警告: Could not load driverClass com.mysql.jdbc.Driver(待解决)
在一个Spring项目中,新建了一个外部属性文件db.properties,在xml文件中利用${}来引用db.properties文件里面的属性. beans-properties.xml: < ...
- ambari-server启动出现ERROR main] DBAccessorImpl:106 - Error while creating database accessor java.lang.ClassNotFoundException:com.mysql.jdbc.Driver问题解决办法(图文详解)
不多说,直接上干货! 问题详情 ambari-server启动时,报如下的错误 问题分析 注:启动ambari访问前,请确保mysql驱动已经放置在/usr/share/Java内且名字是mysql- ...
- Cannot load JDBC driver class 'com.mysql.jdbc.Driver '
最近在学JAVA, SSM, 照着网上的例子系统启动后总是报这个错(IDE :IEDA): HTTP Status 500 - Request processing failed; nested ex ...
- cloudera-scm-server启动出现Error creating bean with name 'entityManagerFactoryBean'与HHH010003: JDBC Driver class not found: com.mysql.jdbc.Driver错误解决办法(图文详解)
不多说,直接上干货! 问题详情 -- ::, INFO main:com.cloudera.server.cmf.Main: Starting SCM Server. JVM Args: [-Dlog ...
- Class.forName("com.mysql.jdbc.Driver") ;
try { Class.forName("com.mysql.jdbc.Driver") ; } catch(ClassNotFoundException e) { System. ...
随机推荐
- ASP.NET Core新书终于上市,完成今年一个目标,赠书活动
2018年.NET Core 2.0发布后,开始逐步学习.NET Core 并逐步在新的项目中使用ASP.NET Core.并且零零散散写的写了将近30篇学习笔记发到园子里,包括ASP.NET Cor ...
- APP自动化-环境安装
环境安装: 需要安装以下工具: 1.appium server-desktop 官方网站下载地址:http://appium.io// 2.安卓ADT(Android Develop Tools) 下 ...
- 如何写出优美的 JavaScript 代码?
一.变量相关 (1)变量数量的定义 NO:滥用变量 let kpi = 4; // 定义好了之后再也没用过 function example() { var a = 1; var b = 2; var ...
- 整理requests和正则表达式爬取猫眼Top100中遇到的问题及解决方案
最近看崔庆才老师的爬虫课程,第一个实战课程是requests和正则表达式爬取猫眼电影Top100榜单.虽然理解崔老师每一步代码的实现过程,但自己敲代码的时候还是遇到了不少问题: 问题1:获取respo ...
- Java (三)APACHE Commons IO 常规操作
上一篇:Java (二)基于Eclipse配置Commons IO的环境 例1:查看文件.文件夹的长度(大小). 1 import java.io.File; 2 3 import org.apach ...
- 项目使用eslint
今天eslint版本更新了,然后昂,有些奇奇怪怪的错误提示了,然后想,这我得 1.配置一个保存时根据eslint规则自动修复 2.欸,之前编码遇到未使用的变量都会有标记黄线,我很好定位,这会怎么没了 ...
- HanLP的分词统计
HanLP的分词效果鄙人研究了HanLP,他的分词效果确实还可以,而且速度也比较快,10的数据是9000毫秒 @SneakyThrows@Overridepublic LinkedHashMap< ...
- mysql任意文件读取漏洞复现
前言 第一次得知该漏洞后找了一些文章去看. 一开始不明白这个漏洞是怎么来的,只知道通过在服务端运行poc脚本就可以读取客户端的任意文件,直接找到网上准备好的靶机进行测试,发现可行,然后就拿别人的poc ...
- Springboot集成JUnit5优雅进行单元测试
为什么使用JUnit5 JUnit4被广泛使用,但是许多场景下使用起来语法较为繁琐,JUnit5中支持lambda表达式,语法简单且代码不冗余. JUnit5易扩展,包容性强,可以接入其他的测试引擎. ...
- Vim最强调试插件:vimspector
最近看到了韦大在知乎的回答后,想去试用一下vimspector,却发现vimspector诞生两年了却没有介绍它的中文资料.我查阅官方文档遇到不少困难,在这里记录折腾出来的结果,与大家分享. vims ...