mysql流式查询_Mybatis流式查询避免OOM
水煮牛肉做法
前⾔
当指定查询数据过⼤时,我们⼀般使⽤分页查询的⽅式,⼀页⼀页的将数据放到内存处理。但有些情况不需要分页的⽅式查询数据,如果⼀下⼦将数据全部加载出来到内存中,很可能会发⽣OOM。这时我们可以使⽤流式查询解决问题。
⾮流式查询
为了更好的复现问题,将jvm参数,最⼤堆设置成212M。使⽤mysql数据库,表⼤⼩为730MB。
⾮流式查询表⾥所有数据代码
List infoPOs = infoMapper.lectList(new EntityWrapper<>());
通过查看idea控制台,很快出现了内存溢出。
通过jconsole⼯具,查看内存使⽤情况
奉天门
在14.26,发现内存直接被释放了。
流式查询
流式查询表⾥所有数据代码
@Select("lect * from t_iot")
@Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = Integer.MIN_VALUE)
@ResultType(InfoPO.class)
void lectAutoList(ResultHandler handler);
infoMapper.lectAutoList(resultContext -> {
});
通过查看idea控制台,程序运⾏正常
付诸一笑
在通过jconsole⼯具,查看内存使⽤情况手绘学习
发现内存消耗处于平稳状态。
流式查询原理
查看源码可知,我们使⽤流式查询时,必须要满⾜以下3个条件
/**
* We only stream result ts when they are forward-only, read-only, and the
* fetch size has been t to Integer.MIN_VALUE
*
* @return true if this result t should be streamed row at-a-time, rather
* than read all at once.
*/
猪心怎么洗才干净protected boolean createStreamingResultSet() {
return ((ResultType() == Type.FORWARD_ONLY) && (sultSetConcurrency ==
java.sql.ResultSet.CONCUR_READ_ONLY)
&& (ResultFetchSize() == Integer.MIN_VALUE));
}
resultSetConcurrency=ResultSet.CONCUR_READ_ONLY 设置只读结果集
一幅美丽的画
resultSetType = ResultSetType.FORWARD_ONLY 设置结果集的游标只能向下滚动
fetchSize = Integer.MIN_VALUE 设置fetch size为int的最⼩值,这⾥和oracle/db2有区别.
Oracle/db2是从服务器⼀次取出fetch size 条记录放在客户端,客户端处理完成⼀个批次后再向服务器取下⼀个批次,直到所有数据处理完成。
mysql在执⾏()⽅法时,会通过数据库连接⼀条⼀条的返回。MySQL按照⾃⼰的节奏不断的把buffer写回⽹络中。flush buffer的过程是阻塞式的,也就是说如果⽹络中发⽣了拥塞,nd buffer被填满,会导致buffer⼀直flush不出去,那MySQL的处理线程会阻塞,从⽽避免数据把客户端内存撑爆。
设置三个参数之后,断点进⼊到了流式返回结果集ResulttRowsStreaming。
ResultSet数据返回的结果,对象有3种实现⽅式
ResulttRowsStatic 静态结果集,默认的查询⽅式,普通查询
ResulttRowsCursor 游标结果集,服务器端基于游标查询
ResulttRowsStreaming 动态结果集,流式查询
查看ResulttRowsStatic类注释
/**
* Reprents an in-memory result t
*/
public class ResulttRowsStatic extends AbstractResulttRows implements ResulttRows {
表⽰放在内存中的结果集。
查看ResulttRowsStreaming类注释
/**
* Provides streaming of Resultt rows. Each next row is consumed from the
* input stream only on {@link #next()} call. Consumed rows are not cached thus
* we only stream result ts when they are forward-only, read-only, and the
* fetch size has been t to Integer.MIN_VALUE (rows are read one by one).
*
* @param
俯卧背起
* ProtocolEntity type
*/
public class ResulttRowsStreaming extends AbstractResulttRows implements ResulttRows {
提供了Resultt⾏的流。获取下⼀⾏都是从仅在{@link #next()}调⽤时输⼊流。因此不会缓存已使⽤的⾏。我们只在结果集只有前进、只读和时才流结果集获取⼤⼩已设置为整数。MIN_VALUE(逐个读取⾏)。
银行利率查询总结
之前使⽤过db2处理流式查询,设置的fetch size为100,没有问题。这次使⽤mysql刚开始时也设置的100,发现内存溢出了,后来在⽹上看到mysql流式获取数据的坑,debug进去果然没⾛到ResulttRowsStreaming类,设置fetch size 参数为Integer.MIN_VALUE后,才进了ResulttRowsStreaming类。