为什么.scroll与无状态会话导致OutOfMemoryException?

时间:2013-08-11 17:58:00

标签: java hibernate out-of-memory

我希望减少hibernate会话的开销(以提高性能,因为会话需要太多时间来处理其存储的对象)并尝试使用无状态会话:

            statelessSession.createQuery(
                    "SELECT me, me.mailSourceFile, me.linf " +
                            "FROM MessageEntry me " +
                            "WHERE me.mailSourceFile.archive.folder = :folder " +
                            "ORDER BY me.messageLength DESC")
                    .setString("folder", folder)
                    .scroll(ScrollMode.FORWARD_ONLY);

但.scroll(...)给出了

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.mysql.jdbc.Buffer.<init>(Buffer.java:59)
    at com.mysql.jdbc.MysqlIO.nextRow(MysqlIO.java:1477)
    at com.mysql.jdbc.MysqlIO.readSingleRowSet(MysqlIO.java:2936)
    at com.mysql.jdbc.MysqlIO.getResultSet(MysqlIO.java:477)

...

我的代码没有memleaks,它可以正常使用Session和.iterator()。我还应该如何使用无状态会话以避免崩溃?

感谢名单。

1 个答案:

答案 0 :(得分:0)

以下是documentation of the MySQL JDBC driver

的摘录
  

默认情况下,ResultSet完全检索并存储在内存中。在大多数情况下,这是最有效的操作方式,并且由于MySQL网络协议的设计更容易实现。如果您正在使用具有大量行或大值的ResultSet,并且无法在JVM中为所需内存分配堆空间,则可以告诉驱动程序一次将结果流回一行。

     

要启用此功能,请按以下方式创建Statement实例:

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                            java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
  

只读的只读结果集与提取大小Integer.MIN_VALUE的组合用作驱动程序逐行传输结果集的信号。在此之后,将逐行检索使用该语句创建的任何结果集。

     

这种方法有一些警告。您必须先读取结果集中的所有行(或关闭它),然后才能对连接发出任何其他查询,否则将抛出异常。

鉴于你只是从MySQL结果集中读取时得到一个OutOfMemoryError,我的猜测是这个结果集在内存中被完全读取,并且足够大以消耗JVM的所有可用内存。