我正在开发一个网站,允许注册用户在10到200万条记录中搜索,这些记录将与许多内存缓存(Java中)进行交叉引用。其中一些缓存只有5000左右,其中一个记录将接近1.8亿条记录。
因此,我只在每个SQL查询中设置了一个索引。有时用户不需要索引,因此Java端将获得一个迭代数据库中每条记录的语句的Integer.MIN_VALUE获取大小。
JSP页面每2秒查询一次进度并更新JavaScript进度条等
一切都很好,而且速度非常快,但是我通过在另一个线程中设置一个volatile布尔值,然后在rs.next()中检查它是否被取消并突破了while循环,并正确关闭数据库资源。
在10万条记录中途,在ResultSet上取消了将近45秒。
在进行一些测试之后,ResultSet.close()方法延迟快速取消以允许用户返回编辑其参数。但是,如果在关闭ResultSet之前取消语句(Statement.cancel()),它将关闭并立即退出搜索。
这是它的要点:
public void search() throws Exception {
total = getSize(where); // where clause created dynamically and depending on options user chooses may be null
current = 0;
Connection c = getConnection();
Statement s = c.createStatement();
s.setFetchSize(Integer.MIN_VALUE);
ResultSet rs = s.executeQuery(queryBuffer.toString()); // potentially a query returning a lot of stuff
logger.info("Full Query " + queryBuffer.toString());
long stime = System.currentTimeMillis();
while (rs.next()) {
Record rec = helper.deriveLightweightRecord(rs);
current++;
if (stack.accept(rec)) { // stack of filters to check records against, one has 180 million records in cache
valid++;
}
if (requestCancel) {
logger.info("Cancel Detected at Search Thread Breaking Now " + System.currentTimeMillis());
break;
}
if (current % 20000 == 0) {
long etime = System.currentTimeMillis();
logger.info("Iterated 20000 Records in " + ((etime - stime) / 1000.0) + " Seconds");
stime = etime;
}
}
try {
if (requestCancel)
s.cancel(); // if i don't call cancel, the result set close takes a LONG time >30secs, calling cancel the ResultSet close takes all of a couple millis
s.close();
rs.close();
} catch (Exception e) {
logger.error("Ignorable for now", e); // occassionally get a SQLException because of cancel
} finally {
returnConnection(c);
}
logger.info("Closed Connection " + System.currentTimeMillis());
if (requestCancel) {
logger.info("Checking Request Cancel Now " + System.currentTimeMillis());
cancelled = true;
searching = false;
cancelNotifier.interrupt();
resetStatus();
} else {
current = total;
searching = false;
}
}
回答这个问题,取消一个Statement有什么后果,因为我之前从未使用过这个函数。 Mysql Connector和Java API上的javadocs并没有真正提到Statement.cancel(),除了它可能会抛出一个不支持的操作异常,如果底层的RDMS不支持它(MySQL似乎)。
在专用的网络服务器上,这会降级还是容易出错?似乎运行正常,除了偶尔抛出一个关于尝试关闭取消语句上的ResultSet的SQLException。在流式传输ResultSet时,这是否会对数据库造成损害?
提前致谢。