繁体   English   中英

将MySQL的大量记录读入Java

[英]Reading large amount of records MySQL into Java

我的MySQL数据库有+800万条需要处理的记录(无法在数据库本身中完成),因此在尝试将它们读入Java应用程序时遇到问题。

我已经尝试过解决类似问题的人的一些解决方案(例如link ),但是没有一个解决方案适合我。 我试图设置FetchSize以及所有设置,但是没有运气! 我的应用程序是利用BlockingQueue构建的,生产者从该BlockingQueue连续读取数据库中的数据,并将其存储在队列中,以便消费者可以对其进行处理。 这样,我可以同时限制主内存中的记录数量。

我的代码适用于少量记录(我测试了1000条记录),因此我建议需要修复从数据库到应用程序的情况。

EDIT1

connection = ConnectionFactory.getConnection(DATABASE);
preparedStatement = connection.prepareStatement(query, java.sql.ResultSet.CONCUR_READ_ONLY, java.sql.ResultSet.TYPE_FORWARD_ONLY);
preparedStatement.setFetchSize(1000); 
preparedStatement.executeQuery();
rs = preparedStatement.getResultSet();

EDIT2

最终,除了看到内存不足之外,我现在得到了一些输出。 我收到此错误:

Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space
at com.mysql.jdbc.Buffer.<init>(Buffer.java:59)
at com.mysql.jdbc.MysqlIO.nextRow(MysqlIO.java:2089)
at com.mysql.jdbc.MysqlIO.readSingleRowSet(MysqlIO.java:3554)
at com.mysql.jdbc.MysqlIO.getResultSet(MysqlIO.java:491)
at com.mysql.jdbc.MysqlIO.readResultsForQueryOrUpdate(MysqlIO.java:3245)
at com.mysql.jdbc.MysqlIO.readAllResults(MysqlIO.java:2413)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2836)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2828)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2777)
at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1651)
at razoralliance.dao.DataDAOImpl.getAllDataRS(DataDAOImpl.java:38)
at razoralliance.app.DataProducer.run(DataProducer.java:34)
at java.lang.Thread.run(Thread.java:722)

EDIT3

我对生产者-消费者模式进行了更多研究,结果发现,当消费者无法跟上生产者时,队列将自动扩大,从而最终耗尽内存。 所以我切换到ArrayBlockingQueue,使大小固定。 但是,我仍然会泄漏内存。 Eclipse内存分析器说ArrayBlockingQueue占我的内存的65.31%,而它在内存中只有1000个对象,而所有文本均为4个字段。

您将需要流式传输结果。 使用MySQL驱动程序,您似乎必须为ResultSet设置CONCUR_READ_ONLYTYPE_FORWARD_ONLY 另外,相应地设置获取大小: stmt.setFetchSize(Integer.MIN_VALUE);

默认情况下,完全检索结果集并将其存储在内存中。 在大多数情况下,这是最有效的操作方式,而且由于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的的读取大小用作信号到驱动器以流结果集一行接一行。 此后,将使用该语句创建的所有结果集逐行检索。

这种方法有一些注意事项...

您为什么不尝试这种方法来解决此问题

使用Java将大量数据从数据库导出到.csv时出现问题

无需获取整个结果集,而是可以一一读取它,然后将其用于处理。 我所指的链接曾经用来一张一张地记录并写入文件,但是您可以使用此结果进行处理。这是您可以使用的一种方法。

另一种方法是您可以使用多线程概念,该概念将根据您的需求获取记录并将单独处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM