一、前言
最近有个需求,需要从一个很大的表中读取数据,每次读取的数据量最大估计为100W条,计算后大概是120M的样子。此表虽然做了分区,但是一次读取100W数据可能会卡住,长时间读不出来。因此采用流式读取的方式,一条一条读取出来。经过实际测试,发现获取100W数据耗时减少了很多。
二、使用方法
第一种办法是借助匿名内部类实现,网上大多介绍是匿名内部类的实现方法,本文不再重复。下面介绍一下我日常用的一种实现方法
建立一个抽象类QueryRecordHandler,里面的execute就是具体每个handler要实现的内容
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
public abstract class QueryRecordHandler implements ResultHandler {
public final Logger logger = LoggerFactory.getLogger(QueryRecordHandler.class);
protected Map<String,String> value = new HashMap<>();
Map<String, Object> row;
protected abstract void execute(Map<String, Object> row);
@Override
public void handleResult(ResultContext context) {
row = (Map<String, Object>) context.getResultObject();
execute(row);
}
public Map<String,String> getValue(){
return this.value;
}
}
然后建立针对某个具体业务实现的handler,塞上你的具体实现。如果你需要传进来某些参数,可以像bean一样,直接声明,并提供set方法,然后在调用的时候,置入值即可。
@Slf4j
public class TransRecordHandler extends QueryRecordHandler {
@Override
protected void execute(Map<String, Object> row) {
Long id = Long.valueOf(row.get("ID").toString());
String bizType = (String) row.get("BIZTYPE");
value.put(id, bizType);
}
}
怎么调用呢?如下:
TransRecordHandler handler = new TransRecordHandler();
handler.setMap(map);
transactionRecordEntityMapper.selectNoFailRecord(参数1, 参数2, 参数3, handler);
return handler.getValue();
还是你原来的查询方法,只是参数新增了一个handler,引入语句import org.apache.ibatis.session.ResultHandler;意思就是查询出来的内容由你自定义的handler处理。
三、注意事项
这里的流式读取只是个抽象概念,实际是保有一个长连接,然后一条一条读取。l另外注意dao层方法不能再有返回值,而是通过handler.getValue()获取。