JDBC流式读取

Posted 唐微港

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDBC流式读取相关的知识,希望对你有一定的参考价值。

业务场景

  1. 在做数据库的相关开发的时候,可能有人面对过这些场景,从一个数据库把大数据量读取出来存放到另外一个数据库、做大数据量的报表、将大数据量的数据读取出来推送到接口。

  2. 因为是大数据量,所以如果直接读取可能会存在OOM的问题,或者直接卡顿,因为使用JDBC连接数据库读取大数据量时候,所有的数据是直接从数据库服务端加载进入了客户端,所以内存占用过大,而且result.next()方法会阻塞。

解决方式

分页

上面的这种情况或许有人会说,数据量大那可以使用分页的方式,的确,甚至可以使用框架的分页,例如mybatis-plus这些。可是存在的问题是,这种方式一样会效率低下,而且上面的场景中可能还没用具体的对象进行关系映射。并且其他框架底层也是基于JDBC的这种方式构建的。

所以这里就只能考虑使用JDBC的方式获取表数据。

流式读取

在使用JDBC连接获取数据时,JDBC为我们提供了一种获取数据的方式叫做流式读取,这个有些类似于java8中的stream流。

            preparedStatement = connctObj.prepareStatement(strSql, ResultSet.TYPE_FORWARD_ONLY,
                    ResultSet.CONCUR_READ_ONLY);
            preparedStatement.setFetchSize(1000);
            preparedStatement.setFetchDirection(ResultSet.FETCH_REVERSE);
            resultSet = preparedStatement.executeQuery();

如上所示其实就是在prepareStatement中加入了ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY,参数中使用了preparedStatement.setFetchSize(1000);和preparedStatement.setFetchDirection(ResultSet.FETCH_REVERSE);

如果这些参数没给JDBC就默认没有开启流式读取,给了setFetchSize,ResultSet.TYPE_FORWARD_ONLY和ResultSet.CONCUR_READ_ONLY就表示开启了流式读取,这样在获取到resultSet中查询结果的时候就不会一次性全部放入内存中,而且效率也比较可观。

注意

preparedStatement.setFetchSize(1000);中的1000最初默认是Integer.MIN_VALUE,例如preparedStatement.setFetchSize(Integer.MIN_VALUE);但是这个是表示每次获取的长度,所以可以换成具体的数字,那个合适还得自己根据实际查询的量拿去试试。

以上是关于JDBC流式读取的主要内容,如果未能解决你的问题,请参考以下文章

JDBC流式读取

JDBC流式读取

JDBC--05--MySQL大数据量操作---常规查询游标查询流式查询,

JDBC批量读取优化-fetchSize

六十三Spark-读取数据并写入数据库

部分代码片段