之前一直对jdbc的query timeout有疑惑,看了下mysql的实现,大概了解了。
关于jdbc的各种超时时间关系见这个文章http://www.importnew.com/2466.html,这里简单来看一下mysql的query timeout实现,也是比较简单。query timeout就是在发起请求前,启动一个定时任务,触发之后抛出异常。
核心代码再执行sql过程中
protected synchronized ResultSetInternalMethods executeInternal(int maxRowsToRetrieve, Buffer sendPacket, boolean createStreamingResultSet, boolean queryIsSelectOnly, Field[] metadataFromCache, boolean isBatch) throws SQLException { try { //恢复超时状态 resetCancelledState(); //物理连接 MySQLConnection locallyScopedConnection = this.connection; this.numberOfExecutions++; if (this.doPingInstead) { doPingInstead(); return this.results; } ResultSetInternalMethods rs; CancelTask timeoutTask = null; try { //如果设置了query timeout,则启动一个timer任务 if (locallyScopedConnection.getEnableQueryTimeouts() && this.timeoutInMillis != 0 && locallyScopedConnection.versionMeetsMinimum(5, 0, 0)) { timeoutTask = new CancelTask(this); locallyScopedConnection.getCancelTimer().schedule(timeoutTask, this.timeoutInMillis); } //这里执行sql,因为mysql是bio的,所以正常的话线程会等待server端返回,要么就socket read timeout抛出异常 rs = locallyScopedConnection.execSQL(this, null, maxRowsToRetrieve, sendPacket, this.resultSetType, this.resultSetConcurrency, createStreamingResultSet, this.currentCatalog, metadataFromCache, isBatch); //如果需要超时,即使服务端正常返回了,还是会抛出超时异常 if (timeoutTask != null) { //先把timer任务停了,大部分情况下超时任务还没到点触发 timeoutTask.cancel(); locallyScopedConnection.getCancelTimer().purge(); //如果在进行超时操作的时候抛出了异常,则直接抛出这个异常 if (timeoutTask.caughtWhileCancelling != null) { throw timeoutTask.caughtWhileCancelling; } timeoutTask = null; } synchronized (this.cancelTimeoutMutex) { if (this.wasCancelled) { SQLException cause = null; //如果被超时处理了,则抛出MySQLTimeoutException if (this.wasCancelledByTimeout) { cause = new MySQLTimeoutException(); } //如果是被cancel了,就抛出cancel异常 else { cause = new MySQLStatementCancelledException(); } //完了之后,重新恢复状态,等待下一次sql请求 resetCancelledState(); //抛出异常 throw cause; } } } finally { //最后的时候,取消超时任务,大部分场景都是正常访问,timer没到点就返回了 if (timeoutTask != null) { timeoutTask.cancel(); locallyScopedConnection.getCancelTimer().purge(); } } return rs; } catch (NullPointerException npe) { checkClosed(); // we can't synchronize ourselves against async connection-close // due to deadlock issues, so this is the next best thing for // this particular corner case. throw npe; } }
具体的超时实现CancelTask
public void run() { //超时的时候,杀连接 if (connection.getQueryTimeoutKillsConnection()) { try { toCancel.wasCancelled = true; toCancel.wasCancelledByTimeout = true; connection.realClose(false, false, true, new MySQLStatementCancelledException(Messages.getString("Statement.ConnectionKilledDueToTimeout"))); } catch (NullPointerException npe) { // not worth guarding against } catch (SQLException sqlEx) { caughtWhileCancelling = sqlEx; } } else { //正常的关闭当前sql请求 Connection cancelConn = null; java.sql.Statement cancelStmt = null; try { synchronized (cancelTimeoutMutex) { //复制一个连接,这里会重新创建新的连接,如果此时db down了,则会connect timeout。然后发送kill指令,如果db down了,发送不成功,抛出异常,此时cancel失败 if (origConnURL == connection.getURL()) { //All's fine cancelConn = connection.duplicate(); cancelStmt = cancelConn.createStatement(); cancelStmt.execute("KILL QUERY " + connectionId); } else { try { cancelConn = (Connection) DriverManager.getConnection(origConnURL, origConnProps); cancelStmt = cancelConn.createStatement(); cancelStmt.execute("KILL QUERY " + connectionId); } catch (NullPointerException npe){ //Log this? "Failed to connect to " + origConnURL + " and KILL query" } } //设置状态,方便主线程进行超时判断 toCancel.wasCancelled = true; toCancel.wasCancelledByTimeout = true; } } //如果超时任务抛出异常,比如db挂了,则给主线程一个异常 catch (SQLException sqlEx) { caughtWhileCancelling = sqlEx; } catch (NullPointerException npe) { // Case when connection closed while starting to cancel // We can't easily synchronize this, because then one thread // can't cancel() a running query // ignore, we shouldn't re-throw this, because the connection's // already closed, so the statement has been timed out. } finally { if (cancelStmt != null) { try { cancelStmt.close(); } catch (SQLException sqlEx) { throw new RuntimeException(sqlEx.toString()); } } if (cancelConn != null) { try { cancelConn.close(); } catch (SQLException sqlEx) { throw new RuntimeException(sqlEx.toString()); } } toCancel = null; origConnProps = null; origConnURL = null; } } }
从上可知,如果发送sql请求之后db挂了,query timeout触发时还没恢复,则query timeout不成功,此时主线程还会等待server端返回直到socket read timeout抛出异常,而如果socket read timeout设置比query timeout小,则query timeout始终无效,因为超时任务还没启动,主线程就抛出socket timeout异常了。
相关推荐
<set-tx-query-timeout>false</set-tx-query-timeout> <blocking-timeout-millis>30000</blocking-timeout-millis> <idle-timeout-minutes>30</idle-timeout-minutes> </timeout> ...
- **Connection Timeout** 和 **Read Timeout**:设置连接和读取超时时间。 2. **mysql-connector-java**:这是MySQL的Java驱动程序,用于在Java应用(比如JMeter)中与MySQL通信。在本例中,提供的压缩包文件`...
### 使用Embulk实现SQL Server至MySQL的数据迁移 #### 一、背景介绍 随着业务发展和技术迭代,企业常常需要在不同的数据库之间进行数据迁移。本文主要介绍如何使用Embulk这一工具来实现从SQL Server到MySQL的数据...
c3p0.checkout_timeout=5000 ``` 这些参数定义了连接池的大小、获取连接的增量、空闲连接测试间隔以及超时设置等。 然后,在Java代码中,我们可以创建C3P0Util工具类,初始化数据源并提供数据库操作的方法: ```...
它允许Java应用程序连接并执行SQL语句,实现数据的CRUD(Create、Read、Update、Delete)操作。本教程将以MySQL数据库为例,介绍如何使用JDBC进行数据库操作。 首先,我们需要理解JDBC的基本步骤: 1. **加载驱动*...
$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 2); // 设置超时时间为2秒 $mysqli->real_connect('127.0.0.1', 'root', '', 'test'); ``` 执行SQL语句可以通过`$mysqli->query()`方法完成。对于无结果集的SQL(如...
query.timeout=10000 ``` 7. **其他高级配置**:根据具体数据库驱动,可能还有其他特定参数,如自动提交、字符编码等: ``` autoCommit=true characterEncoding=utf-8 ``` 在Java程序中,我们通常会使用`...
6. **其他配置**:还可以包含其他特定的属性,比如自动提交的设置(autocommit)、事务隔离级别(transaction isolation level)、查询超时时间(query timeout)等。 在Java项目中,我们通常会使用`Properties`类...
idle-timeout: 18000 # 最大连接数,默认10 maximum-pool-size: 10 # 从连接池返回的连接自动提交 auto-commit: true # 连接最大存活时间,0表示永久存活,默认1800000(30分钟) max-lifetime: 1800000 # ...
- **Query timeout**:设置查询超时时间。 - **Handle result set**:定义如何处理Callable Statements返回的结果。 ### 示例:SELECT请求 对于一个简单的SELECT查询,如`SELECT * FROM plf_users`,在设置好JDBC ...
- `connection-timeout`: 获取连接的最大等待时间(毫秒)。 - `connection-test-query`: 用于测试连接的SQL语句。 **3.3 创建实体和仓库** 如果使用Spring Data JPA,可以创建一个实体类和对应的仓库接口: ```...
- **Pool Timeout**:连接池中的连接等待时间。 - **Idle Cleanup Interval**:定义了连接池清理空闲连接的时间间隔,即如果一个连接超过这个时间没有被使用,则会被自动关闭。 - **AutoCommit**:决定数据库操作...
#hibernate.c3p0.timeout 5000 #hibernate.c3p0.max_statements 100 #hibernate.c3p0.idle_test_period 3000 #hibernate.c3p0.acquire_increment 2 #hibernate.c3p0.validate false ############################...
@Value("${spring.datasource.druid.remove-abandoned-timeout}") private int removeAbandonedTimeout; @Bean public DruidDataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); ...
proxool.mytestdriver.create-timeout=30000 proxool.mytestdriver.test-query=SELECT 1 ``` 然后在代码中加载这个配置并初始化Proxool,如下所示: ```java Properties props = new Properties(); props.load(new...
System.out.println("ID: " + id + ", Name: " + name); } ``` #### 第五章:数据库工具类JdbcUtils ##### 5.1 需求: 为了简化数据库操作,可以创建一个工具类`JdbcUtils`,用来封装数据库连接的创建和关闭逻辑...
spring.datasource.hikari.connection-timeout=30000 # 获取连接的超时时间(毫秒) spring.datasource.hikari.connection-test-query=SELECT 1 # 用于测试连接是否有效的SQL查询 ``` 这些配置项定义了数据库连接池...
- **`timeout`**:连接超时时间(单位毫秒)。 ##### 5. 数据源配置 ```yaml spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql:...
<jp:mondrianQuery dataSource="" id="query01" jdbcDriver="oracle.jdbc.driver.OracleDriver" jdbcUrl="jdbc:oracle:thin:ngykt/ngyktadmin@172.16.46.241:1521:orcl10" catalogUri="/WEB-INF/queries/feeSchema....