MySQL JDBC 驱动在未配置流式读取或游标相关参数的情况下,默认会使用静态结果集进行数据的接收,其中源码位于 MysqlIO.java at release/5.1:
1 | private RowData readSingleRowSet(long columnCount, int maxRows, int resultSetConcurrency, boolean isBinaryEncoded, Field[] fields) throws SQLException { |
可以看出,使用 ArrayList
将行记录存储至内存中,然后包装为 RowDataStatic
对象返回给调用方。在大多数情况下,这是最有效的实现方式,但是,在对大批量数据的导出过程中,上面的实现方式要求内存必须足以容纳本次查询的结果集,否则会触发 OOM,如果需要解决该问题,可以优化为使用流式读取,使用如下方式创建 Statement
:
1 | stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, |
经过以上的设置,接收的结果集实例即为 RowDataDynamic
对象,源码可以参考:MysqlIO.java at release/5.1,关键部分代码为:
1 | if (!streamResults) { |
RowDataStatic
类与 RowDataDynamic
类最显著的差别在 next
方法的实现,其中 RowDataStatic
的 next
方法源码如下:
1 | private int index; |
可以看出,调用 RowDataStatic
对象的 next
方法时,是直接读取的之前整个结果集读取到内存中的 List<ResultSetRow> rows
中的数据。
RowDataDynamic
类的 next
方法实现源码如下:
1 | /** |
其中 nextRecord
为从数据库获取下一条记录,此处不再粘贴源码,此种实现方式无需单次获取结果集的全部数据至内存,降低了内存占用。
还有一种方式就是使用游标,具体可以查看下方链接。
Reference
MySQL :: MySQL Connector/J 5.1 Developer Guide :: 5.4 JDBC API Implementation Notes