java.lang.OutOfMemoryError:执行数百万个查询时出现 Java 堆空间错误

发布于 2024-12-03 09:02:26 字数 569 浏览 0 评论 0原文

在我的应用程序中,我需要对 MySQL 数据库执行数百万次查询。代码如下所示:

for (int i=0; i< num_rows ; i++) {
   String query2="select id from mytable where x='"+ y.get(i) "'";              
   Statement stmt2 = Con0.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);     
   ResultSet rs2 = stmt2.executeQuery(query2);    
   ... // process result in rs2
   rs2.close(); 
}

其中 num_rows 约为 200 万。 600k循环后,java报错并退出:

java.lang.OutOfMemoryError:Java 堆空间错误。

我的代码有什么问题?我应该如何避免这样的错误?

提前致谢!

In my application, I need to perform millions of queries to MySQL database. The codes look as follows:

for (int i=0; i< num_rows ; i++) {
   String query2="select id from mytable where x='"+ y.get(i) "'";              
   Statement stmt2 = Con0.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);     
   ResultSet rs2 = stmt2.executeQuery(query2);    
   ... // process result in rs2
   rs2.close(); 
}

where num_rows is around 2 million. After 600k loops, java report an error and exit:

java.lang.OutOfMemoryError: Java heap space error.

What's wrong in my codes? How should I avoid such an error?

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

睫毛溺水了 2024-12-10 09:02:26

也结束你的陈述。

Close your statements as well.

束缚m 2024-12-10 09:02:26

声明在这里并不是一个好的解决方案。尝试以下代码:

PreparedStatement pre = Con0.prepareStatement("select id from mytable where x=?");

for (int i=0; i< num_rows ; i++) {
   pre.setString(1, y.get(i));
   ResultSet rs2 = pre.executeQuery();
   ... // process result in rs2
   rs2.close(); 
   pre.clearParameters();
}
pre.close();

Statement is no good solution here. Try the following code:

PreparedStatement pre = Con0.prepareStatement("select id from mytable where x=?");

for (int i=0; i< num_rows ; i++) {
   pre.setString(1, y.get(i));
   ResultSet rs2 = pre.executeQuery();
   ... // process result in rs2
   rs2.close(); 
   pre.clearParameters();
}
pre.close();
沉默的熊 2024-12-10 09:02:26

我不知道您接受的答案是否解决了您的问题,因为它并没有改变任何可能导致问题的内容。

问题是当 ResultSet 缓存查询返回的所有行时,这些行可以在迭代集合时存储,也可以预取。我在 PostgreSQL JDBC 驱动程序中遇到了类似的问题,在非事务模式下运行时,该驱动程序忽略了游标获取大小。

JDBC 驱动程序应使用游标 进行此类查询,因此您应该检查有关fetchSize 参数的驱动程序文档。或者,您可以自己管理游标,执行 SQL 命令来创建游标并获取接下来的 X 行。

I don't know if the answer accepted by you have solved your problem, since it doesn't change anything that could cause the problem.

The problem is when ResultSet is caching all the rows returned by the query, which can either be stored while you iterate through set, or prefetched. I've had similar problem with PostgreSQL JDBC driver, which ignored the cursor fetch size, when running in no-trasactional mode.

The JDBC driver should use cursors for such queries, so you should check driver's documentation about fetchSize parameter. As alternative, you can manage cursors yourself executing SQL command to create cursor and fetch next X rows.

碍人泪离人颜 2024-12-10 09:02:26

使用preparedStatement,因为每个循环中只有X的值发生变化,所以在de循环之外声明应该会有所帮助。至少在显示的代码中,您也没有关闭使用的语句,这可能无助于垃圾收集器释放已使用的内存。

Using a preparedStatement, since only the value of X changes in each loop, declared outside de loop should help. You're also, at least in the shown code, not closing the statement used, which might not help the garbage collector to free the used memory.

漫漫岁月 2024-12-10 09:02:26

假设您对所有查询使用单个连接,并且假设您的代码比您向我们展示的代码更复杂,那么确保每个 Statement 和每个 ResultSet 在完成后关闭是至关重要的。这意味着您需要这样的 try/finally 块:

for (int i=0; i< num_rows ; i++) {
  String query2="select id from mytable where x='"+ y.get(i) "'";              
  Statement stmt2 = Con0.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);     
  ResultSet rs2 = null;   
  try {
    rs2 = stmt2.executeQuery(query2);    
    ... // process result in rs2
  } finally {
    try {
      stmt2.close();
    } catch (SQLException sqle) {
      // complain to logs
    }
    try {
      if (rs2 != null) { rs2.close(); }
    } catch (SQLException sqle) {
    }
  }
}

如果您不积极且确定性地关闭所有结果集和语句对象,并且如果您足够快地发出请求,那么您将耗尽内存。

Assuming that you are using a single connection for all your queries, and assuming your code is more complicated than what you show us, it is critical that you ensure that each Statement and each ResultSet is closed when you are finished with it. This means that you need a try/finally block like this:

for (int i=0; i< num_rows ; i++) {
  String query2="select id from mytable where x='"+ y.get(i) "'";              
  Statement stmt2 = Con0.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);     
  ResultSet rs2 = null;   
  try {
    rs2 = stmt2.executeQuery(query2);    
    ... // process result in rs2
  } finally {
    try {
      stmt2.close();
    } catch (SQLException sqle) {
      // complain to logs
    }
    try {
      if (rs2 != null) { rs2.close(); }
    } catch (SQLException sqle) {
    }
  }
}

If you do not aggressively and deterministically close all result set and statement objects, and if you do requests quickly enough, you will run out of memory.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文