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

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

``

```java
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文件:

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

### 自定义一个ResultHandler:

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

```java
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;
}
}
```

### 使用代码示例:

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

## **结言**

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

MyBatis 在大数据量下使用流式查询进行数据同步的更多相关文章

  1. Mysql中使用JDBC流式查询避免数据量过大导致OOM

    一.前言 java 中MySQL JDBC 封装了流式查询操作,通过设置几个参数,就可以避免一次返回数据过大导致 OOM. 二.如何使用 2.1 之前查询 public void selectData ...

  2. c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习

    c#中@标志的作用   参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...

  3. 大数据量查询容易OOM?试试MySQL流式查询

    一.前言 程序访问 MySQL 数据库时,当查询出来的数据量特别大时,数据库驱动把加载到的数据全部加载到内存里,就有可能会导致内存溢出(OOM). 其实在 MySQL 数据库中提供了流式查询,允许把符 ...

  4. 大数据量下,分页的解决办法,bubuko.com分享,快乐人生

    大数据量,比如10万以上的数据,数据库在5G以上,单表5G以上等.大数据分页时需要考虑的问题更多. 比如信息表,单表数据100W以上. 分页如果在1秒以上,在页面上的体验将是很糟糕的. 优化思路: 1 ...

  5. 达观数据CTO纪达麒:小标注数据量下自然语言处理实战经验

    自然语言处理在文本信息抽取.自动审校.智能问答.情感分析等场景下都有非常多的实际应用需求,在人工智能领域里有极为广泛的应用场景.然而在实际工程应用中,最经常面临的挑战是我们往往很难有大量高质量的标注语 ...

  6. 实现 MyBatis 流式查询的方法

    基本概念流式查询指的是查询成功后不是返回一个集合而是返回一个迭代器,应用每次从迭代器取一条查询结果.流式查询的好处是能够降低内存使用.如果没有流式查询,我们想要从数据库取 1000 万条记录而又没有足 ...

  7. MyBatis 如何实现流式查询

    基本概念 流式查询指的是查询成功后不是返回一个集合而是返回一个迭代器,应用每次从迭代器取一条查询结果.流式查询的好处是能够降低内存使用. 如果没有流式查询,我们想要从数据库取 1000 万条记录而又没 ...

  8. MyBatis 流式查询

    流式查询指的是查询成功后不是返回一个集合而是返回一个迭代器,应用每次从迭代器取一条查询结果.流式查询的好处是能够降低内存使用. 流式查询的过程当中,数据库连接是保持打开状态的,因此要注意的是:执行一个 ...

  9. Spark SQL - 对大规模的结构化数据进行批处理和流式处理

    Spark SQL - 对大规模的结构化数据进行批处理和流式处理 大体翻译自:https://jaceklaskowski.gitbooks.io/mastering-apache-spark/con ...

  10. 浅谈PageHelper插件分页实现原理及大数据量下SQL查询效率问题解决

    前因:项目一直使用的是PageHelper实现分页功能,项目前期数据量较少一直没有什么问题.随着业务扩增,数据库扩增PageHelper出现了明显的性能问题.几十万甚至上百万的单表数据查询性能缓慢,需 ...

随机推荐

  1. python调用方法或者变量时出现未定义异常的原因,可能会是没有正确实例化

    当引用某个某块时 例如 Testpython import test class test(object): def __init__(): -- self.mimi = test def test1 ...

  2. Cocos 引擎生态部负责人李阳:己之所欲,可施于人,希望通过生态促进国内引擎技术发展

    前言 "小小的身体,大大的能量,这个应该是我对大表姐最直接的感觉,在她娇小的身躯里蕴含了无限的精力和潜力,很像漫威里的神奇女侠,作为一个具备冒险精神的非典型程序员,大表姐热爱的体育活动都是很 ...

  3. 阿里云OSS前端直传+net core后端签名

    OSS前端直传+后端签名 一.服务端签名后前端直传 首先安装阿里云SDK Aliyun.OSS.SDK.NetCore public static string accessKeyId = " ...

  4. vue-i18n警告

    vue3引入vue-i18n警告: bundler build of vue-i18n. It is recommended to configure your bundler to explicit ...

  5. 超全 泛微 E9 Ecology 9开发资料大全 开源资源下载 泛微E9二次开发 泛微开发实战经验 泛微开发实战例子 泛微二次开发项目例子 泛微二次开发Demo 泛微二次开发完整例子 泛微二次开发入门

    由于工作需要,E9在泛微一推出来,以前所在的企业就第一时间上线了,经过四年多的运行,功能强大再加上在上面开发非常多的业务,一般的企业员工只需要打开泛微就可以处理完平时信息化的业务.后来又去外包公司专业 ...

  6. 2023年php面试题

    Php面试题 1.isset和empty的区别? Isset测试变量是否被赋值,如果这个变量没被赋值,则返回false,empty是判断变量是否为空,当赋值为0,null,'',返回true为真.他们 ...

  7. vue之事件修饰符

    目录 修饰符 .stop事件 .self事件 .prevent事件 .once事件 修饰符 事件修饰服 释义 .stop 只处理自己的事件,子控件不再冒泡给父控件 .self 只处理自己的事件,子控件 ...

  8. Python多线程与GIL锁

    Python多线程与GIL锁 python多线程 Python的多线程编程可以在单个进程内创建多个线程来同时执行多个任务,从而提高程序的效率和性能.Python的多线程实现依赖于操作系统的线程调度器, ...

  9. CentOS 6.8 安装 node 后报错,显示 gcc 版本过低

    因为测试服务器要部署一个 vue 的环境,安装了 node 和 npm 后,却由于 gcc 动态库版本过低,导致报错如下 node: /usr/lib64/libstdc++.so.6: versio ...

  10. 面向接口编程实践之aspnetcoreapi的抽象

    最为一名越过菜鸟之后的开发,需要做接口开发.下面做一个纯粹的接口编程的实例demo,仅仅是一个webapi接口的抽象. 下面是代码接口,AbsEFWork是webapi,BaseEntityFrame ...