mybatis 流式读取大量MySQL数据

 JDBC从数据库获取数据的三种读取方式:
1.一次全部(默认):一次获取全部。
2.流式:多次获取,一次一行。
3.游标:多次获取,一次多行。

mybatis没有任何配置的话是采取第一种方式 当数据量比较大的时候 容易引发oom

现在介绍第二种:流式获取数据

代码示例 

mapper 层:

mybatis 流式读取大量MySQL数据

/**
 * @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为

mybatis 流式读取大量MySQL数据框中的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 &gt;= #{startTime}
    and create_time &lt; #{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 实现类为

mybatis 流式读取大量MySQL数据红框中可以添加单条处理逻辑

/**
 * @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));
        }
    }
}