`

如何停止超时的DB查询

阅读更多

一.问题:有时我们执行的DB查询(例如一些查询的存储过程)会时间太长,当我们的代码逻辑上不想等待这么长时间时,怎么删除呢?

 

二.思考:首先想到使用"select connectionId()",然后通过"kill query id"语句来删除掉对应的DB进程.后来发现JdbcTemplate里面CallableStatement的cancel()可以关掉存储过程的调用.那么我们可以结合Timer来计时,当超过N分钟后,就执行cancel()即可.

 

三.代码:

1.定义一个task:(可以配合connectionId来做追踪,虽然逻辑上没有使用上)

public class CustomTimeTask extends TimerTask {
	private static final Logger logger = LoggerFactory.getLogger(CustomTimeTask.class);
	
	CallableStatement cs ;
	int id;
	
	public CustomTimeTask(CallableStatement cs, int id) {
		super();
		this.cs = cs;
		this.id = id;
	}

	@Override
	public void run() {
		try {
			logger.info("[Timeout]TimeTask try to cancel the long time procedure query. Connection ID is [{}]", id);
			cs.cancel();
		} catch (Exception e) {
			logger.error("[Timeout]TimeTask fail to cancel the long time procedure query. Please check the if the query has been stopped in database. "
					+ "The connection ID is [{}]", id);
		}
	}

}

 

2.执行:

logger.debug("-----------Start to call CSV store procedure------------");
		Connection conn = null;
		CallableStatement cs = null;
		ResultSet rs = null;
		
		Timer timer = null;
		boolean isQuery = false;
		
	......
		try{
			conn = jdbcTemplate.getDataSource().getConnection();
			cs = conn.prepareCall(foo);
			....
			
			isQuery = true;
			int queryTimeoutMins = SystemConfig.getQueryTimeout();
			if(queryTimeoutMins>0) {
				logger.debug("Execute the statemnet to call procedure  to connection ID [{}]. "
					+ "And start the timer to cancel the timeout query. Timeout setting [{} minutes]"
						,conID,queryTimeoutMins);
				CustomTimeTask customTimeTask = new CustomTimeTask(cs, conID);
				timer = new Timer();
				timer.schedule(customTimeTask, queryTimeoutMins * 60 * 1000);
			}else {
				logger.debug("Execute the statemnet to call procedure to gen CSV record to connection ID [{}]. "
						+ "But not start the timer to cancel the timeout query because timeout setting is [{} minutes]"
						,conID,queryTimeoutMins);
			}
			
			cs.execute();
			if(timer != null) {
				logger.debug("The query for connection ID [{}] is completed. "
					+ "Cancel the timer and begin to get the resultSet. ",conID);
				timer.cancel();
				timer.purge();
			}else {
				logger.debug("The query for connection ID [{}] is completed. Begin to get the resultSet.",conID);
			}
			isQuery = false;
			
			rs = cs.getResultSet();
			
			.........
			
			...........
			
			rs.close();
		}catch (DataAccessException e) {
			dbLogger.error("DB is down. Exception is [{}]", e.getMessage());
			try {
				if(isQuery && cs!=null && !cs.isClosed()) {
					logger.info("Program has begun the query. Try to cancel the procedure query for connection ID [{}]"
							, conID);
					cs.cancel();
				}
				
			} catch (MySQLStatementCancelledException e1) {
				logger.info("Successfully cancel the procedure query for connection ID [{}]"
						, conID);
				if(timer != null) {
					timer.cancel();
					timer.purge();
				}
				isQuery = false;
			} catch (Exception e1) {
				logger.error("-- Error occur when try to cancel the query for connection ID[{}]. "
						+ "Exception is [{}].",conID, e.getMessage());
			}
			throw e;
			
		} catch (MySQLStatementCancelledException e) {
			logger.info("Successfully cancel the procedure query for connection ID [{}]"
					, conID);
			if(timer != null) {
				timer.cancel();
				timer.purge();
			}
			isQuery = false;
			return null;
		}catch (Exception e) {
			logger.error("-- Error occur, exception is [{}]", e.getMessage());
			logger.error("DB: error:", e);
			try {
				if(isQuery && cs!=null && !cs.isClosed()) {
					logger.info("Program has begun the query. Try to cancel the procedure query for connection ID [{}]"
							, conID);
					cs.cancel();
				}
				
			} catch (MySQLStatementCancelledException e1) {
				logger.info("Successfully cancel the procedure query for connection ID [{}]"
						, conID);
				if(timer != null) {
					timer.cancel();
					timer.purge();
				}
				isQuery = false;
			} catch (Exception e1) {
				logger.error("-- Error occur when try to cancel the query for connection ID[{}]. "
						+ "Exception is [{}].",conID, e.getMessage());
			}
			
			return null;
		}finally {
			try {
				if (rs != null)
					rs.close();
				if (cs != null)
					cs.close();
				if (conn != null) {
					conn.close();
				}
			} catch (Exception e) {
				logger.error("Error occurs when close the connection to database. Error:", e);
				return null;
			}
			
		}
		logger.debug("-----------End to call store procedure------------");
		return resultMap;
	}

 

有几个地方值得注意,省略号的地方就正常cs执行存储过程的处理.但是对于timer要做判断:

1.如果查询结束了,那就没必要等待schedule了,要把timer取消掉

2.如果DB错误,判断是否在查询并且确定cs是否close,否则要调用cs.cancel()来结束

3.同时,注意cs.cancel()后,timer有没有结束

分享到:
评论

相关推荐

    DB2 9.5 中的锁定超时分析新方法

    DB2 9.5 中的锁定超时分析新方法: 激活 DB2 9.5 中的锁定超时报告 db2set DB2_CAPTURE_LOCKTIMEOUT=ON db2stop db2start

    jdbc连接db2

    Connection conn = DriverManager.getConnection(DbSource,"administrator","123456789"); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * from sales"); if (rs....

    Berkeley DB的java版本

    Berkeley DB Java Edition JE 是一个完全用JAVA写的 它适合于管理海量的 简单的数据 能够高效率的处理1到1百万条记录 制约JE数据库的往往是硬件系统 而不是JE本身 多线程支持 JE使用超时的方式来处理线程间的死琐...

    Berkeley DB Java Edition 4.1.10.zip

    Berkeley DB Java Edition (JE)是一个完全用JAVA写的,它适合于管理海量的,简单的数据。 能够高效率的处理1到1百万条记录,制约JE数据库的往往是硬件系统,而不是JE本身。 多线程支持,JE使用超时的方式来处理...

    sqlncli.msi

    Microsoft SQL Server Native Client (SQL Native Client) 是单一动态链接库 (DLL),包含 SQL OLE DB 提供程序和 SQL ODBC 提供程序。它还对使用本机代码 API(ODBC、OLE DB 和 ADO)的应用程序提供运行时支持,以与...

    db:db 模块的 Kanso 包

    这包括文档 CRUD 操作、查询视图和创建/删除数据库。 安装 将db添加到kanso.json的依赖项部分。 ... "dependencies" : { "db" : null , ... } 运行kanso install来获取包 您还需要将jQuery包含在您的页面中...

    Berkeley_DB_Java_Edition.zip_海量 数据

    Berkeley DB Java Edition (JE)是一个完全用JAVA 写的,它适合于管理海量的,简单的 数据。 l 能够高效率的处理 1 到 1 百万条记录,制约 JE 数据库的往往是硬件系统,而不是 JE 本身。 多线程支持,JE 使用超时的...

    解决PHP mysql_query执行超时(Fatal error: Maximum execution time …)

    本篇文章是对解决PHP mysql_query执行超时(Fatal error: Maximum execution time of 300 seconds exceeded in…)的问题进行了详细的分析介绍,需要的朋友参考下

    System.Data.OleDb.OleDbException: 未指定的错误的完美解决方法

    异常详细信息: System.Data.OleDb.OleDbException: 未指定的错误 这个错误是access数据库特有的错误,当access频繁读取或操作过多的时候就会发生这个错误,微软官方已找不到具体的解决方法,网上搜索了很多,可以...

    Java中数据库驱动程序加载及建立连接

    Java开发中DB2、Oracle、SQL Server、Sybase、MySQL等数据库的驱动程序的加载及建立连接

    rust-dbqueue

    服务器使用事件循环 ( mio ) 来管理客户端连接、接受器和超时,并使用 Futures( eventual )来同步事件。 在tests/examples/server.rs有一个设置默认服务器的tests/examples/server.rs ,在tests/examples/client...

    MongoDB游标超时问题的4种解决方法

    handler = pymongo.MongoClient().db.col for row in handler.find(): parse_data(row) 短短4行代码,读取MongoDB里面的每一行数据,然后传入parse_data做处理。处理完成以后再读取下一行。逻辑清晰而简单,能有...

    Provider错误80004005终极解决方法(完全有效的方法)

    Microsoft OLE DB Provider for ODBC Drivers 错误 ‘80004005’ [Microsoft][ODBC Microsoft Access Driver]常见错误 不能打开注册表关键字 ‘Temporary (volatile) Jet DSN for process 0x728 Thread 0x854 DBC 0x...

    DBeaver sql格式化V1.4

    DBeaver工具很强大,但在sql格式化方面不尽人意,所以利用它的扩展功能开发出来的一个功能。说明文档: ...1、首选项中找到:sql编辑器->sql格式化 ,【格式...勾选使用临时文件,超时时间2000毫秒 2、要求java jdk1.8及以上

    Redis 用法

    设置超时 SETEX key_with_time 10 "same values" ttl key_with_time ttl key_with_time get key_with_time 如果服务器返回 OK ,那么这个客户端获得锁。 如果服务器返回 NIL ,那么客户端获取锁失败,可以在稍后再...

    SQL做的数据库《图书管理系统》

    三:还书记录(借阅证号,归还时间,超时天数,图书号,借出时间) 借阅清单(借出时间,归还时间,借阅证号,图书号) 四:借书历史清单(图书号,借出时间,借阅证号) 还书记录(借阅证号,归还时间,超时天数,...

    LINUX FTP设置方法

    #data_connection_timeout=120 /*连接超时时间*/ #nopriv_user=ftpsecure #async_abor_enable=YES #ascii_upload_enable=YES /*是否使用ascii格式上传*/ #ascii_download_enable=YES /*是否使用ascii格式下载*/ ...

    完整的REORG表的过程

    db2 中对于出现死锁或锁超时的解决方案

    InsCache:多级缓存高并发查询Redis缓存进程缓存

    原理比较简单,举个例子:1000个键为a的请求和1000个键为b的请求同时发生,先从进程内查询a,b,如果没有获取到则查询Redis(如果配置了Redis),如果再没有数据则查询Db,那么完全只有有2条请求(a和b)进入Redis /...

    mongodb-university:Mongod DB大学课程

    审计与最佳实践稽核减少日志安全检查表 诊断和调试服务器日志服务器状态工具服务器诊断工具探查器指数统计响应时间下降吞吐量下降应用程序更改的影响慢查询修复丢失的索引连接超时连接性分片问题模式调查 ...

Global site tag (gtag.js) - Google Analytics