前言
流式查询指的是查询成功后不是返回一个集合,而是返回一个迭代器,应用每次从迭代器取一条查询结果。流式查询的好处是能降低内存的使用。
如果没有使用流式查询,我们想要从数据库取1000万条记录而又没有足够的内存时,就不得不分页查询,而分页查询效率取决于表设计,如果设计得不好是,就无法高效的分页查询。因此流式查询是一个数据库访问框架必须具备的功能。
流式查询的过程当中,数据库连接是保持打开状态的,因此要注意的是:执行一个流式查询后,数据库访问框架就不负责关闭数据库连接了,需要应用在取完数据后自己关闭。
SpringBoot中应用
- UserMapper
/**
* 流式查询所有user
* @return 返回的类型是游标类型
* 当查询百万级的数据的时候,使用游标可以节省内存的消耗,不需要一次性取出所有数据,可以进行逐条处理或逐条取出部分批量处理。
*/
Cursor<User> selectAll2(); //返回的是游标对象类型
- UserMapper.xml
在Mapper映射文件的标签中加入fetchSize=100 。因为mybatis默认是把所有数据全部查询出后返回,这样容易造成OOM问题(内存溢出),这时,我们设置一下fetchSize,设置每次查询出多少条数据,之后再执行next方法,读取下一批数据,这样每次查询出来一点,就处理一点,就不容易造成OOM问题了。
<!--加上fetchSize-->
<select id="selectAll2" resultType="com.age.batch.batchuser.entity.User" fetchSize="100">
select id,username,age,sex,address from user
</select>
- UserService
/**
* 流式查询所有user
* @return
*/
Cursor<User> selectAdd2();
- UserServiceImpl
/**
* 流式查询所有user
* @return
*/
@Override
public Cursor<User> selectAdd2() {
return userMapper.selectAll2();
}
- controller
@ApiOperation("流式查询所有user,测试查询时间")
@GetMapping("/selectall2")
@Transactional //注意要使用@Transactional注解来维持数据库连接,否则当recordMapper查询结束后数据库连接就会断开,Cursor就取不到数据了
public void selectAll2(){
Cursor<User> users = userService.selectAdd2();
users.forEach(user -> System.out.println(user));
}
5000条数据,普通查询下的耗时为1366毫秒,流式查询下的耗时为76毫秒