【问题标题】:Caching Data in HashMap (Connection, ResultSet, and Statement is opened after getting Data from it and put in the Map)HashMap 中缓存数据(Connection、ResultSet、Statement 获取数据后打开并放入 Map)
【发布时间】:2012-02-29 06:09:58
【问题描述】:

在我的应用程序中,我需要在HashMapTreeMap 中输入cache 数据,这可以节省大量时间,因为每次从DB server 获取记录并处理它是非常耗时的任务。
我也在使用JProfiler 对此应用程序进行分析,我觉得当我从DataBase 获取记录以放入MapResultSet 的连接时,Statement 没有关闭,因为它正在向我展示这些classes 占用了这么多内存。
这是我对此反应过度还是真的有问题?
顺便说一句,我正在关闭finally block 中的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() 方法---

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);
    }
}

【问题讨论】:

  • 为什么不使用任何缓存 API 以更灵活、更高效的方式为您做到这一点?
  • 但问题又是为什么我的分析器显示这些数据库类,即使我已经关闭了它们。
  • 你能展示HMDBUtil.close方法吗?
  • @LuiggiMendoza 我已将其发布在问题中
  • 是的,它确实有助于垃圾收集器。它可以在方法结束之前计算出它可以收集哪些对象。但是,在您的实现中它不起作用,因为您将 references 设置为 null 以传递给 close 方法的连接和语句。实际对象仍然无法收集,因为它们已在 someFunction 方法中引用。

标签: java performance caching memory jprofiler


【解决方案1】:

关闭连接后,结果集和语句不会立即从堆中删除。您需要至少运行一次垃圾收集器才能发生这种情况。

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

+1 用于使用 3rd 方缓存提供程序。

编辑:只是为了避免混淆。类将存在于堆中,直到您处理结束,并将驻留在Permanent Generation

类(对象)的实例应该被垃圾回收。如果它们不意味着您的进程以某种方式在某处保存了对它们的引用,或者没有运行垃圾收集器。

我不确定 JProfiler,但使用 YourKit,您可以轻松导航对象图并找到哪个对象包含对未收集对象的引用。它在过去发现内存泄漏方面帮助了我很多。

【讨论】:

  • 我已经对其进行了多次监控,并且我确信在 GC 之后调用这些类而不是 GC。是的,HMDBUtil.close() 方法很好,我将 Statement、Resultset 和 Connection 作为参数,并在方法中一一关闭。
【解决方案2】:

在所有的 try 块执行完毕后最终执行,所以当你执行 "testMap.put(rs.getString(1).trim(), rs.getString(2));" 时是正常的ResultSet 和 Statement 已打开,因为您尚未关闭它们。

【讨论】:

  • 我的尝试块已经完成。我通过上面给定的方法返回了一张地图,我得到了完美的结果。表示执行了 Try 块。
  • 但是你报告的问题是当你把东西放在地图上时,不是吗? “我觉得当我从数据库中获取记录以放入到 ResultSet 的 Map 连接中时,Statement 没有关闭”这是在 try 中执行的,并且在关闭之前执行。
  • 我想我描述错了,但就像当我完成我的数据库活动时,这些对象也在堆上
猜你喜欢
  • 1970-01-01
  • 2012-01-13
  • 2015-11-21
  • 1970-01-01
  • 2010-11-05
  • 2013-10-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多