Mybatis游标查询
通常对一张表中大量数据处理时由于数据量太大都要使用分页分批查询处理,否则数据量太大会导致OOM等问题,但是如果不能使用分页时怎么进行处理,这是后就要使用Mybatis游标Cursor查询
原理
Cursor实现了Closeable和Iterable接口,我们可以通过迭代器来获取数据进行处理
示例
查询语句
在Mapper上写上对应的查询语句
//PriceIndexEntity是查出的实体对象
//ResultSetType表示游标的滚动模式 resultSetType = ResultSetType.FORWARD_ONLY 只能向前滚动
//fetchSize表示每次执行的记录数 fetchSize = Integer.MIN_VALUE
public interface CursorDemoMapper extends BaseMapper<PriceIndexEntity> {
@Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = Integer.MIN_VALUE)
@Select("select * from t_scf_price_index ")
Cursor<PriceIndexEntity> scrollResult();
}
业务处理
public class DemoService implements IBusinessService{
@Resource
SqlSessionFactory sqlSessionFactory;
@Override
public void doVerify(ServiceHandlerContext context) {
}
@Override
public void doWork(ServiceHandlerContext context) {
try( //对应mysql数据库不会自动开启连接 所以需要手动开启连接,执行完成后自动关闭连接
SqlSession sqlSession=sqlSessionFactory.openSession();
//2、在连接中开启游标查询
Cursor<PriceIndexEntity> priceIndexEntities = sqlSession.getMapper(CursorDemoMapper.class).scrollResult();) {
//buffer的大小建议设置在1000左右。
AtomicInteger index= new AtomicInteger(1);
int bufferSize=1000;
List<PriceIndexEntity> buffer =new ArrayList<>(bufferSize);
priceIndexEntities.forEach(priceIndexEntity -> {
//将查出的数据放到buffer中
buffer.add(priceIndexEntity);
if(index.getAndIncrement() ==bufferSize){
//业务处理
doPartWork(buffer);
buffer.clear();
index.set(1);
}
});
//处理最后不足1000的数据
if(buffer.size()>0){
doPartWork(buffer);
}
} catch (IOException e) {
log.error("XXX查询异常:【{}】",e.getMessage(),e);
}
ServiceHandlerContextExt.createSuccessResponseWithMsg(this,context,"sd");
}
public void doPartWork(List<PriceIndexEntity> buffer){
//业务处理 System.out.println("================================="+buffer.size());
}