GBase 8a采用流模式处理JDBC大结果集,避免内存不足 OutOfmemoryError: GC overhead limit exceeded

GBase 8a数据库,支持jdbc开发接口,如果查询结果集很大,则会占满本地jre的内存,最终导致outofmemoryError, 可以采用流模式解决。

报错样例

java.lang.OutOfMemoryError: GC overhead limit exceeded

内存不足,垃圾回收超过限制次数了。

解决方案

因为jdbc默认是将所有结果集都缓冲到本地,以便提供前进,后退的双向移动功能,但会占用大量内存。如果业务上只有前进(next),则可以采用每次只读取最小单位数据,处理完了再读取下一部分,来减少内存的消耗。

这个问题,对任何数据库都存在。

ResultSet.TYPE_FORWARD_ONLY, 表示只会前进,不会后退。
ResultSet.CONCUR_READ_ONLY 表示数据只读,不会更新。
setFetchSize 指定每次读取的最小值,一行一行的处理。注意,这里Integer.MIN_VALUE隐藏了含义,一般都是流模式的开关。如果改成其它数字,请做详尽的测试确保内存使用符合要求。

Statement stat = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stat.setFetchSize(Integer.MIN_VALUE);  

提示

如果你读取一行,处理一行,而且处理一行数据时间过长,会导致服务器端发送数据超时,请参考

警告

请尽量不要开启服务器端游标,除非你做了详尽的测试。

因为服务器端游标,是将结果集【先缓冲到服务器上】,再返回调用方,来实现前后移动。而一个超大结果集,可能占用几百G,几T,甚至几十T的磁盘空间。

关键是,这个空间,会落在【一台】(连接节点)服务器上,有极大概率会撑爆磁盘空间。