在HashMap中缓存数据(在获取数据并将其放入Map中之后打开Connection、ResultSet和Statement)

3
在我的应用程序中,我需要在 HashMap 或 TreeMap 中缓存数据,这样可以节省大量时间,因为从 DB 服务器获取记录并处理它是非常耗时的任务。
我还使用 JProfiler 对此应用程序进行分析,我感觉从 DataBase 获取记录以放入 Map 时,ResultSet 和 Statement 的连接未关闭,因为它显示这些类占用了很多内存。
这是我反应过度了还是确实存在问题?
顺便说一下,在 finally 块中关闭 connection。以下是代码。
public Map someFunction() throws SomeException{
Connection con=null;
    Statement stmt=null;
    ResultSet rs=null;
    String sql=null;
    Map <String,String> testMap=new TreeMap<String, String>();

    try {
        con=HMDBUtil.getConnection();
        if(cacheSize==0) {
            sql = "SELECT SOMETHING FROM SOMEWHERE";
        }else {
            sql = "SELECT SOMETHING FROM SOMEWHERE_ELSE where rownum<"+cacheSize;
        }
        stmt=con.createStatement();
        stmt.setFetchSize(100000);
        rs=stmt.executeQuery(sql);
        long count=0;
        while(rs.next()) {
            testMap.put(rs.getString(1).trim(), rs.getString(2));
            count++;
        }
    } catch (SQLException e) {

        log.fatal("SQLException while fetching Data",e);
        throw new SomeException("SQLException while fetching Data",e);          
    }finally {
        HMDBUtil.close(con, stmt, rs);
    }

    return testMap;
}

HMDBUtil.close() method---

public static void close(Connection con, Statement stmt, ResultSet rs)
        throws SomeException {
    if (log.isDebugEnabled())
        log.debug("Invoked");
    close(rs);
    close(stmt);
    close(con);

    if (log.isDebugEnabled())
        log.debug("Leaving");
}

所有关闭连接的方法 --

    public static void close(Connection con) throws SomeException {
    try {

        if (log.isDebugEnabled())
            log.debug("Invoked");
        if (con != null) {
            con.close();
            con = null;
        }

        if (log.isDebugEnabled())
            log.debug("Leaving");

    } catch (SQLException e) {
        log.fatal("SQLException while Closing connection ", e);
        throw new SomeException("SQLException while Closing connection ",
                e, false, true);
    }
}


public static void close(Statement stmt) throws SomeException {
    try {
        if (log.isDebugEnabled())
            log.debug("Invoked");

        if (stmt != null) {
            stmt.close();
            stmt = null;
        }
        if (log.isDebugEnabled())
            log.debug("Leaving");

    } catch (SQLException e) {
        // log.error("Exception while Closing statement ", e);
        log.fatal("SQLException while Closing statement ", e);
        throw new SomeException("SQLException while Closing statement ", e, false, true);

    }
}


public static void close(ResultSet rs) throws SomeException {

    try {
        if (log.isDebugEnabled())
            log.debug("Invoked");
        if (rs != null) {
            rs.close();
            rs = null;
        }
        if (log.isDebugEnabled())
            log.debug("Leaving");

    } catch (SQLException e) {
        log.fatal("SQLException while Closing rs", e);
        throw new SomeException("SQLException while Closing rs", e, false, true);
    }
}

3
为什么不使用任何缓存API以更加灵活高效地完成这个任务? - Umesh Awasthi
但问题是为什么我的分析器显示这些数据库类,即使我已经关闭了它们。 - NIVESH SENGAR
1
你能展示一下 HMDBUtil.close 方法吗? - Luiggi Mendoza
1
是的,它确实有助于垃圾收集器。它可以在方法结束之前确定可以收集哪些对象。但是,在你的实现中它不会起作用,因为你正在将传递给_close_方法的连接和语句的_references_设置为null。实际对象仍然无法被收集,因为它们在_someFunction_方法中被引用。 - Petro Semeniuk
@umesh Awasthi 有什么推荐的缓存API吗? - ImranRazaKhan
显示剩余3条评论
2个回答

3

在关闭连接之后,结果集和语句不会立即从堆中删除。需要运行垃圾回收至少一次才能实现。

此外,您确定HMDBUtil.close()方法按预期工作吗?它也可能泄露连接。

+1使用第三方缓存提供程序。

编辑: 只是为了避免混淆。类将存在于堆中,直到您的进程结束,并驻留在永久代中。

类的实例(对象)应该进行垃圾回收。如果没有,那就意味着您的进程以某种方式在某个地方持有对它们的引用,或者垃圾回收器尚未运行。

我不确定JProfiler,但使用YourKit可以轻松导航对象图并找到保留对未收集对象引用的对象。过去这帮助我发现了内存泄漏问题。


我已经多次监测过了,确信在GC调用后这些类没有被GC。是的,HMDBUtil.close()方法没问题,我将Statement、Resultset和Connection作为参数传入,并在该方法中逐一关闭它们。 - NIVESH SENGAR

1

在try块的所有执行之后最终执行,因此当您执行“testMap.put(rs.getString(1)。trim(),rs.getString(2));”时,ResultSet和Statement仍然处于打开状态,这是正常的,因为您尚未关闭它们。


我的 Try 块已经完成了。我正在通过上述给定的方法返回一个 map,而且我可以完美地获取它。这意味着 Try 块已经被执行。 - NIVESH SENGAR
但是您报告的问题是在向地图中添加内容时出现的,是吗?“我觉得当我从数据库获取记录并将其放入地图中时,ResultSet和Statement连接没有关闭”。这是在try内执行的,并且在关闭之前。 - Pau
我觉得我描述得不太准确,但是当我完成我的数据库操作后,这些对象仍然在堆上。 - NIVESH SENGAR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接