【发布时间】:2014-03-17 11:03:43
【问题描述】:
拥有一个包含 +800 万条记录的 MySQL 数据库,我需要处理(这在数据库本身中无法完成),我在尝试将它们读入我的 Java 应用程序时遇到问题。
我已经尝试了一些有类似问题的人的解决方案(例如,link),但是没有一个适合我。我试图设置 FetchSize 和所有,但没有运气!我的应用程序是使用 BlockingQueue 构建的,生产者从数据库中连续读取数据,将其存储在队列中,以便消费者可以处理它。这样我可以同时限制主内存中的记录数量。
我的代码适用于少量记录(我测试了 1000 条记录),所以我建议需要修复从数据库到我的应用程序的 fase。
编辑1
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();
编辑2
最终,除了看到我的记忆力下降之外,我得到了一些输出。我收到此错误:
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)
编辑3
我对 Producer-Consumer 模式做了一些研究,结果发现,当 Consumer 跟不上 Producer 时,队列会自动扩大,最终导致内存耗尽。所以我切换到 ArrayBlockingQueue ,它使大小固定。但是,我仍然会出现内存泄漏。 Eclipse Memory Analyzer 说 ArrayBlockingQueue 占用了我 65,31% 的内存,而它在内存中只有 1000 个对象,其中 4 个字段都是文本。
【问题讨论】:
-
您能否详细说明该处理的作用?
-
@fge,这是我需要进行文本分类的项目。所以在数据库中是我数据的原始表示。通过处理,我必须删除无用的信息以改进文本分类阶段。所以删除停用词,标记化,...
-
您是否调用了 Statement.setMaxRows(0) 以使 ResultSet 没有限制?
-
你没有得到任何错误或异常,发布它们!
-
Fetch 大小对内存消耗没有影响,它只影响执行的网络往返次数。