调用Statement.cancel()的分支在Java / MySQL中强制关闭大ResultSet

时间:2011-07-25 19:42:16

标签: java mysql resultset

我正在开发一个网站,允许注册用户在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时,这是否会对数据库造成损害?

提前致谢。

0 个答案:

没有答案