本文已springboot项目为例,要实现流式查询需要完成以下几步
POM文件中的配置
springboot中整合mybatis
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
mapper.xml文件配置
select语句需要增加fetchSize属性,底层是调用jdbc的setFetchSize方法,查询时从结果集里面每次取设置的行数,循环去取,直到取完。默认size是0,也就是默认会一次性把结果集的数据全部取出来,当结果集数据量很大时就容易造成内存溢出。
<select id="selectGxids" resultType="java.lang.String" fetchSize="1000">
SELECT gxid from t_gxid
</select>
自定义ResultHandler来分批处理结果集
package flowselect;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import java.util.Set;
public class GxidResultHandler implements ResultHandler<String> {
// 这是每批处理的大小
private final static int BATCH_SIZE = 1000;
private int size;
// 存储每批数据的临时容器
private Set<String> gxids;
public void handleResult(ResultContext<? extends String> resultContext) {
// 这里获取流式查询每次返回的单条结果
String gxid = resultContext.getResultObject();
// 你可以看自己的项目需要分批进行处理或者单个处理,这里以分批处理为例
gxids.add(gxid);
size++;
if (size == BATCH_SIZE) {
handle();
}
}
private void handle() {
try {
// 在这里可以对你获取到的批量结果数据进行需要的业务处理
} finally {
// 处理完每批数据后后将临时清空
size = 0;
gxids.clear();
}
}
// 这个方法给外面调用,用来完成最后一批数据处理
public void end(){
handle();// 处理最后一批不到BATCH_SIZE的数据
}
}
serviceImpl类中的使用
package flowselect;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
@Service
public class ServiceImpl implements Service {
@Autowired
SqlSessionTemplate sqlSessionTemplate;
public void method(){
GxidResultHandler gxidResultHandler = new GxidResultHandler();
sqlSessionTemplate.select("flowselect.Mapper.selectGxids", gxidResultHandler);
gxidResultHandler.end();
}
}
总结
非流式查询:内存会随着查询记录的增长而近乎直线增长。
流式查询:内存会保持稳定,不会随着记录的增长而增长。其内存大小取决于批处理大小BATCH_SIZE的设置,该尺寸越大,内存会越大。所以BATCH_SIZE应该根据业务情况设置合适的大小。
另外要切记每次处理完一批结果要记得释放存储每批数据的临时容器,即上文中的gxids.clear();