java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > MyBatis流式查询

详解MyBatis如何在大数据量下使用流式查询进行数据同步

作者:知北游z

通常的数据同步中,如果数据量比较少的话可以直接全量同步,但是如果数据量很大的话,全量同步需要大量的内存,所以本文为大家介绍了MyBatis使用流式查询实现数据同步的方法,希望对大家有所帮助

通常的数据同步中,如果数据量比较少的话可以直接全量同步,默认情况下,完整的检索结果集会将其存储在内存中。在大多数情况下,这是最有效的操作方式,并且由于 MySQL 网络协议的设计,因此更易于实现。但是如果数据量很大的话,全量同步需要大量的内存,如果内存不足的话则可能会导致内存溢出。

通常的会采用分页的方式,一批一批的同步,大体的实现方式如下:

int page = 1;
int pageNum = 1000;
while (true){
    UserQueryRequest request = new UserQueryRequest();
    request.setPage(page);
    request.setPageSize(pageNum);
    PageInfo<User> pageInfo = userMapper.getUserPage(request);
    if (CollectionUtils.isEmpty(pageInfo.getList()) ){
        break;
    }
    List<User> userList = pageInfo.getList();
    // 具体的处理逻辑 省略
    page ++;
}

这种实现方式虽然可以实现分批同步,但是同步的数据必须先提供实现分页的查询方式,如果数据源是通过复杂的连表查询来的,先实现一个分页查询更是会增加实现的复杂度。解决这个问题可以使用一种更为优雅的解决方式,即使用流失查询。

流式查询,会建立长连接,利用服务端游标,每次读取一条加载到 JVM 内存,因此不会导致内存溢出。

MyBatis 如何使用流式查询:

配置mapper.xml文件:

<select id="selectUsers" resultType="User" fetchSize="1000">
   SELECT userId from t_user
 </select>

自定义一个ResultHandler:

User是自定义的同步对象的实体对象,需要自己定义

import lombok.extern.slf4j.Slf4j;
import model.User;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: jie
 * @create: 2023/3/29 16:51
 * @description:
 */
@Slf4j
public class SyncDataHandler implements ResultHandler<User> {

    /**
     * 每批处理数量
     */
    private final static int BATCH_SIZE = 1000;

    /**
     * 缓存数据
     */
    private List<User> cacheList = new ArrayList<>();

    /**
     * 同步熟虑
     */
    private int total = 0;


    @Override
    public void handleResult(ResultContext<? extends User> resultContext) {
        User coreInfoCyDTO =  resultContext.getResultObject();
        this.cacheList.add(coreInfoCyDTO);
        //每到达BATCH_SIZE 条数据处理一次
        if (this.cacheList.size() >= BATCH_SIZE) {
            this.handle();
        }
        total++;
    }


    /**
     * 处理缓存数据
     */
    private void handle() {
        try {
            // 具体的处理逻辑 省略
        } finally {
            // 清除处理过的缓存数据
            this.cacheList.clear();
        }
    }

    /**
     * 处理最后一批没有进行处理的数据
     */
    public int end() {
        this.end();
        return total;
    }
}

使用代码示例:

SyncDataHandler syncDataHandler = new SyncDataHandler();
userMapper.getUserList("selectUsers", syncDataHandler);
syncDataHandler.end();

结言

流式查询可以避免 OOM,,数据量大可以考虑此方案,其占用内存大小取决于批处理大小BATCH_SIZE的设置。所以BATCH_SIZE应该根据业务情况设置合适的大小。但是这这种方式会占用数据库连接,使用中不会释放,所以线上针对大数据量业务用到流式操作,一定要进行并发控制。

到此这篇关于详解MyBatis如何在大数据量下使用流式查询进行数据同步的文章就介绍到这了,更多相关MyBatis流式查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文