mybatis 流式读取大量MySQL数据
JDBC从数据库获取数据的三种读取方式:
1.一次全部(默认):一次获取全部。
2.流式:多次获取,一次一行。
3.游标:多次获取,一次多行。
mybatis没有任何配置的话是采取第一种方式 当数据量比较大的时候 容易引发oom
现在介绍第二种:流式获取数据
代码示例
mapper 层:
/** * @author zhanglf */ @Mapper public interface OdsWwPersReceiptAcctDtMapper{ void getExportInfosByDateByHandler(@Param("financialContractUuids") List<String>financialContractUuids, @Param("startTime") Date startTime, @Param("endTime") Date endTime, OdsExportResultHandler resultHandler); }
对应mapper.xml为
框中的fetchSize需要为-2147483648 流式获取才会生效
<select id="getExportInfosByDateByHandler" parameterType="map" resultType="com.suidifu.ods.export.model.OdsWwPersReceiptAcctDtModel" fetchSize="-2147483648"> select * from ods_ww_pers_receipt_acct_dt where data_status=0 and create_time >= #{startTime} and create_time < #{endTime} <if test="null!=financialContractUuids and financialContractUuids.size()>0"> and financial_contract_uuid in <foreach item="item" index="index" collection="financialContractUuids" open="(" separator="," close=")"> #{item} </foreach> </if> </select>
还需要继承ResultHandler 实现类为
红框中可以添加单条处理逻辑
/** * @param <T,K> * @author zhanglf */ @AllArgsConstructor @NoArgsConstructor @Log4j2 public class OdsExportResultHandler<T extends OdsCommModel> implements ResultHandler<T> { private int total=0; /** * 每批处理的大小 */ private int batchSize = 100; private int size; private OdsDataType type; private String odsLocalPath; private boolean existData = false; private OutputStreamWriter writer; private BufferedReader reader; /** * 存储每批数据的临时容器 */ private List<T> ods = new ArrayList<>(); public OdsExportResultHandler(int size, OdsDataType type,String odsLocalPath,OutputStreamWriter writer,BufferedReader reader) { this.batchSize = size; this.type = type; this.odsLocalPath = odsLocalPath; this.writer =writer; this.reader=reader; } @Override public void handleResult(ResultContext resultContext) { T od = (T) resultContext.getResultObject(); existData = true; ods.add(od); size++; if (size == batchSize) { handle(); } } private void handle() { try { log.info("OdsExportResultHandler deal type[{}] size[{}], start.",type.getName(),ods.size()); dealDataToLocal(ods, type,odsLocalPath,writer,reader); log.info("OdsExportResultHandler deal type[{}] size[{}], end. 目前共处理[{}]条",type.getName(),ods.size(),total+ods.size()); } catch (Exception e) { e.printStackTrace(); log.error("导出失败"); } finally { size = 0; ods.clear(); } } public void end() { if (CollectionUtils.isEmpty(ods) && existData) { return; } handle(); } public void closeBuffer(){ try { writer.close(); reader.close(); }catch(Exception e){ log.error("文件关闭失败 reason is [{}]",ExceptionUtils.getStackTrace(e)); } } }