被问傻了:从MySQL读取100w数据进行处理,怎么做?
背景
数据迁移 数据导出 批量处理数据
常规查询: 一次性读取 100w 数据到 JVM 内存中,或者分页读取 流式查询:建立长连接,利用服务端游标,每次读取一条加载到 JVM 内存(多次获取,一次一行) 游标查询: 和流式一样,通过 fetchSize 参数,控制一次读取多少条数据(多次获取,一次多行)
一、常规查询
@Mapperpublic interface BigDataSearchMapper extends BaseMapper<BigDataSearchEntity> {@Select("SELECT bds.* FROM big_data_search bds ${ew.customSqlSegment} ")Page<BigDataSearchEntity> pageList(@Param("page") Page<BigDataSearchEntity> page, @Param(Constants.WRAPPER) QueryWrapper<BigDataSearchEntity> queryWrapper);}
二、流式查询
执行一个流式查询后,数据库访问框架就不负责关闭数据库连接了,需要应用在取完数据后自己关闭 必须先读取(或关闭)结果集中的所有行,然后才能对连接发出任何其他查询,否则将引发异常
Cursor 是可关闭的 Cursor 是可遍历的
isOpen(): 用于在取数据之前判断 Cursor 对象是否是打开状态。只有当打开时 Cursor 才能取数据 isConsumed(): 用于判断查询结果是否全部取完 getCurrentIndex(): 返回已经获取了多少条数据
三、游标查询
@Mapperpublic interface BigDataSearchMapper extends BaseMapper<BigDataSearchEntity> {// 方式一 多次获取,一次多行@Select("SELECT bds.* FROM big_data_search bds ${ew.customSqlSegment} ")@Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 1000000)Page<BigDataSearchEntity> pageList(@Param("page") Page<BigDataSearchEntity> page, @Param(Constants.WRAPPER) QueryWrapper<BigDataSearchEntity> queryWrapper);// 方式二 一次获取,一次一行@Select("SELECT bds.* FROM big_data_search bds ${ew.customSqlSegment} ")@Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 100000)@ResultType(BigDataSearchEntity.class)void listData(@Param(Constants.WRAPPER) QueryWrapper<BigDataSearchEntity> queryWrapper, ResultHandler<BigDataSearchEntity> handler);}
ResultSet.FORWORD_ONLY:结果集的游标只能向下滚动 ResultSet.SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变 ResultSet.SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变 fetchSize:每次获取量
@ResultType(BigDataSearchEntity.class):转换成返回实体类型
方式一是多次查询,一次返回多条 方式二是一次查询,一次返回一条
非流式查询:内存会随着查询记录的增长而近乎直线增长 流式查询:内存会保持稳定,不会随着记录的增长而增长。其内存大小取决于批处理大小BATCH_SIZE的设置,该尺寸越大,内存会越大。所以BATCH_SIZE应该根据业务情况设置合适的大小