我需要将从jdbc结果集获取的约5000万行写入csv文件。
写入csv文件的150万行约为1GB。
jdbcTemplate.query(new CustomPreparedStatementCreator(arg), new ResultSetExtractor<Void>() {
@Override
public Void extractData(ResultSet rs) {
while (rs.next()) {
// transform each row's data (involves creation of objects)
// write the transformed strings to csv file
}
}
问题是我有一个8gb的堆,它很快就被填满了。
因此,在到达1000万行之前,我遇到了java.lang.outofmemoryerror。
我的另一个限制是查询读/写超时,设置为30分钟。
如何回收和重用jvm堆内存?
尤其是分配给我不再需要的对象的内存。
我读到强制gc运行并不能保证内存会被回收。
我有什么选择?我应该把责任推给非gc语言吗
像c,c++通过jna或jni来处理结果集?
[编辑]看来我处境艰难:d添加更多信息,正如@rzwitserloot所指出的
我正在从连接到数据湖的数据虚拟化工具中读取(仅限部分查询)数据。
数据虚拟化工具的jdbc驱动程序确实支持limit,但查询是由业务部门设计的,用于返回大量数据。因此,我有一个镜头拉数据,并生成一个csv-这意味着,我不能避免巨大的选择或把一个限制条款
我需要检查这些属性: resultSetType
, resultSetConcurrency
, resultSetHoldability
.
我已经做了:
首先,我使用producer-consumer模式将jdbc获取操作与慢速文件写入操作分开。这有助于在30分钟超时前创建包含100-500万行的csv文件。
第二,我增加了用户线程的数量,让它们写入自己的单独部分文件,然后合并到单个csv文件中。这加快了文件写入速度,并在30分钟超时前创建了一个包含1000-2000万行的csv文件。
我在resultTextRactor中创建对象,并通过有界队列将其传递给使用者线程。一旦这些对象中的数据写入文件,就不需要这些对象了。
1条答案
按热度按时间xuo3flqw1#
你粘贴了很少的代码;其中一个关键的线索是,通过设计,您粘贴的代码没有内存问题-resultset是有意设计为游标式的,从理论上讲,这意味着
.next()
调用会导致tcp/ip通信,要求数据库获取另一行。这就是为什么需要关闭resultsets(因为数据库正在维护一个单独的“版本”),这样,假设您使用的是serializable或其他一些clean reads隔离级别,那么任何其他启动的事务(或者更确切地说,当你打开一个你正在使用的*时,对你正在浏览的数据没有任何影响.next()
电话。现在,jdbcapi也非常灵活。例如,这需要大量的数据包、通信量和工作,因此在实践中,许多dbjdbc驱动程序要么一次发送所有数据,resultset.close什么也不做,要么至少会以更大的批处理发送数据,而且大多数
.next()
除了每100次呼叫或诸如此类的情况外,所有呼叫都不会产生db通信量。因此,我们有两个主要的选择:
内存泄漏与您粘贴的内容无关;例如,您正在将csv数据写入一个不断增长的缓冲区,而您根本不将其流式传输到磁盘。再检查一下。用limit子句替换giant select,并在其周围添加giant for循环,以模拟编写大量记录,而实际上不需要从jdbc循环中查询太多内容。如果内存仍然不足,那就不是数据库层了。
尽管如此,jdbc驱动程序仍然在用一些持续占用内存的东西来实现它的resultset实现。
如果是#2,则有两种解决方案:
使数据库引擎不这样做。结果集具有“功能”,您可以在制作它们时询问需要哪些功能。例如,您可以告诉系统您希望结果集是所谓的“仅向前”。最有可能导致非内存咀嚼结果集的3个属性是使用
resultSetType = FORWARD_ONLY
,resultSetConcurrency = CONCUR_READ_ONLY
,和resultSetHoldability = CLOSE_CURSORS_AT_COMMIT
. 实际上,我不知道如何告诉jdbctemplate这样做,但应该不会太难——jdbctemplate正在调用java.sql.Connection
的prepareStatement
方法-确保它调用将所有属性设置为这些值的方法。如果这样做不起作用,就解决它,使用offset/limit(很遗憾,这种语法取决于db引擎)一次获取页面。当然,如果在执行此操作时正在编辑表,除非您设置了可序列化事务级别,否则这会弄乱您的内容,并且您必须添加某种形式的order by子句,否则您将无法获得实际的保证结果以相同的顺序返回(如果没有这些,偏移量/限制分页并不能满足您的需要)。这有点奇怪-如果这种情况发生在您身上,您使用的是哪种奇特的三流糟糕的db引擎和/或jdbc驱动程序?