概述

本篇博客是记录使用spring batch做数据迁移时时遇到的一个关键问题:数据迁移量大时如何保证内存。当我们在使用spring batch时,我们必须配置三个东西: reader,processor,和writer。其中,reader用于从数据库中读数据,当数据量较小时,reader的逻辑不会对内存带来太多压力,但是当我们要去读的数据量非常大的时候,我们就不得不考虑内存等方面的问题,因为若数据量非常大,内存,执行时间等等都会受到影响。关于spring batch的基础知识和介绍请参考这篇博客:批处理框架spring batch介绍及使用。

问题是什么

在上面的内容当中我们已经提到了,我们面临的问题是数据迁移量大时的内存问题。但是这样的描述非常笼统,因此博主决定将这一部分单独拎出来说。

在学习了spring batch的知识之后我们应该很清楚的一点是,每一个spring batch的step都包含如下的部分:

即读数据,处理数据,写数据。这三个步骤里面最可能会导致内存变大问题的无疑是读数据环节。读数据作为spring batch的数据输入,是整个spring batch job的开头逻辑。

若我们的数据量不大,如只有几十万条,那我们无疑不会面临内存问题,即便一次将所有数据加载到内存当中,占的内存也不会非常多,且spring batch数据迁移的速度非常之快,几十万条的数据往往是几十秒的时间就可以迁移完成。但是当数据量变大之后,问题就不一样了。当我们的数据量达到数百万或上千万时,若一次性将所有数据全部读到内存当中,则会占据远远超出正常范围的非常大的内存。该问题示意图如下所示:

我们写的任何程序都会有一个运行内存,假设这个内存的总容量现在只有4g,而我们数据库里需要操作的数据有8g,那么无疑,一次性的将数据读出来就会出错。这便是需要考虑得问题。

Spring提供的reader实现

spring提供了非常丰富的Reader实现,其中比较常用的从数据库读数据的有JdbcCursorItemReader,JdbcPagingItemReader等。

JdbcCursorItemReader

使用JdbcCursorItemReader的示例代码如下:

@Bean

public JdbcCursorItemReader itemReader() {

return new JdbcCursorItemReaderBuilder()

.dataSource(this.dataSource)

.name("creditReader")

.sql("select ID, NAME, CREDIT from CUSTOMER")

.rowMapper(new CustomerCreditRowMapper())

.build();

}

JdbcCursorItemReader的好处在于使用简单,但是我们从它的sql就能发现,JdbcCursorItemReader会一次把所有的数据全部拿回来,当数据量过大而服务器内存不够时,就会遇到下面无法分配内存的问题:

报错信息为:Resource exhaustion event:The JVM was unable to allocate memory from the heap. 意思就是需要分配内存的数据太多,但是无法找到足够的内存了。

反映在内存里,堆内存会呈现出如下的情况:

随着每一次数据读入,堆内存都会增大,原因就在于JdbcCursorItemReader一次性读回了所有的数据,返回之后就会存在一个对象里面,而这个对象的尺寸过大,因此直接进入了老年代。在数据迁移完成之前,这些数据都不会被回收。如下图所示:

毫无疑问,当我们的数据量大时不应该使用这种类型的reader来读取数据。

JdbcPagingItemReader

JdbcPagingItemReader的作用和它的名字一样,它可以分页读取数据,但是使用起来相比于JdbcCursorItemReader更加复杂,示例代码如下:

@Bean

public JdbcPagingItemReader itemReader(DataSource dataSource, PagingQueryProvider queryProvider) {

Map parameterValues = new HashMap<>();

parameterValues.put("status", "NEW");

return new JdbcPagingItemReaderBuilder()

.name("creditReader")

.dataSource(dataSource)

.queryProvider(queryProvider)

.parameterValues(parameterValues)

.rowMapper(customerCreditMapper())

.pageSize(1000)

.build();

}

@Bean

public SqlPagingQueryProviderFactoryBean queryProvider() {

SqlPagingQueryProviderFactoryBean provider = new SqlPagingQueryProviderFactoryBean();

provider.setSelectClause("select id, name, credit");

provider.setFromClause("from customer");

provider.setWhereClause("where status=:status");

provider.setSortKey("id");

return provider;

}

可以看到我们能够设置page的大小,JdbcPagingItemReader将根据这个页的大小,每次读取这么多的数据,因此这些数据返回保存的对象,就只会是小对象,因此他们不会直接在老年代里分配,而是先分配在年轻代,随着年轻代不断变大,minor gc也不断进行,回收掉已经处理完的数据,老年代的内存使用量不会有任何增大,类似下图:

老年代内存不会有任何变化,年轻带会随着服务器数据迁移进行而增大同时被回收。

在使用JdbcPagingItemReader时,有一个必须注意的地方就是排序关键字是必须指定的,原因在于排序是分页实现原理的技术基础。sortKey和我们指定的其他字句一起构建出SQL语句出来。在sortKey上必须使用unique key constraint约束,因为只有这样才能得以确保执行之间不会丢失任何数据。这也可以说是JdbcCursorItemReader相对便利的一点优势。

总结

数据量小时选择的方案差别不会很大,当数据量大时,为了有好的内存表现则使用分页的reader是必要的。但同时,因为要实现分页,也会带来一些不可避免的限制。

到此这篇关于spring batch使用reader读数据的内存容量问题详解的文章就介绍到这了,更多相关spring batch使用reader读数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

java数据读取容量,spring batch使用reader读数据的内存容量问题详解相关推荐

  1. Java数据持久层框架 MyBatis之API学习六(Mapper XML 文件详解)

    对于MyBatis的学习而言,最好去MyBatis的官方文档:http://www.mybatis.org/mybatis-3/zh/index.html 对于语言的学习而言,马上上手去编程,多多练习 ...

  2. 数据批处理神器-Spring Batch(1)简介及使用场景

    数据批处理神器-Spring Batch(1)简介及使用场景 tags: springbatch 1.引言 最近使用Spring Batch进行做数据迁移.数据同步.数据批处理等工作,感叹Spring ...

  3. java spring mvc 上传_Java Spring MVC 上传下载文件配置及controller方法详解

    下载: 1.在spring-mvc中配置(用于100M以下的文件下载) 下载文件代码 @RequestMapping("/file/{name.rp}") public Respo ...

  4. Pandas读取和将数据存储到多个sheet的excel以及read_excel函数常用参数详解

    Pandas读取和将数据存储到多个sheet的excel以及read_excel函数常用参数详解 Excel数据显示: read_excel函数常用参数详解 1.io 读取路径 个人比较喜欢第一种(r ...

  5. Java 内存模型 JMM 详解

    转载自 Java 内存模型 JMM 详解 JMM简介 Java Memory Model简称JMM, 是一系列的Java虚拟机平台对开发者提供的多线程环境下的内存可见性.是否可以重排序等问题的无关具体 ...

  6. Java内存模型(JMM)详解

    在Java JVM系列文章中有朋友问为什么要JVM,Java虚拟机不是已经帮我们处理好了么?同样,学习Java内存模型也有同样的问题,为什么要学习Java内存模型.它们的答案是一致的:能够让我们更好的 ...

  7. Reader entry: ���� 乱码详解

    Reader entry: ���� 乱码详解 1.问题描述 2.问题分析 3.问题解决 系统:Win10 JDK:1.8.0_333 IDEA:2020.3.4 1.问题描述 在一次写 MyBati ...

  8. Java多线程系列(九):CountDownLatch、Semaphore等4大并发工具类详解

    之前谈过高并发编程系列:4种常用Java线程锁的特点,性能比较.使用场景 ,以及高并发编程系列:ConcurrentHashMap的实现原理(JDK1.7和JDK1.8) 今天主要介绍concurre ...

  9. 关于Spring 任务调度之task:scheduler与task:executor配置的详解

    关于Spring 任务调度之task:scheduler与task:executor配置的详解 其实就是Spring定时器中配置文件中一些配置信息,由于笔者自己是头一次使用,有些配置详细不太明白,随即 ...

  10. 一篇运维老司机的大数据平台监控宝典(1)-联通大数据集群平台监控体系进程详解

    一篇运维老司机的大数据平台监控宝典(1)-联通大数据集群平台监控体系进程详解 "如果你是一个经验丰富的运维开发人员,那么你一定知道ganglia.nagios.zabbix.elastics ...

最新文章

  1. WebGIS在行业中应用的演变
  2. mysql基础(二)—— 简单sql
  3. ppt科研绘图 图形布尔运算
  4. 计算机网络基础:网络标准相关知识介绍
  5. RMQ求区间最值 nlog(n)
  6. Python Hello World入门 - Python零基础入门教程
  7. linux命令行的操作符,如何在Linux命令行中进行基本的数学运算
  8. Prompt范式,真香
  9. 你真的了解JAVA的形参和实参吗?
  10. Atitit dubbo使用总结 attilax总结 艾龙 总结 1. 概念 1 1.1. Dubbo提供的注册中心有如下几种类型可供选择: 2 1.1.1. Multicast注册中心 2 1.1
  11. Tableau超市数据分析报告
  12. nltk.stem 词干提取(stemming)
  13. 上楼梯问题+不死兔子
  14. 快速排序详细图解分析(含代码示例)
  15. PID控制器的优缺点和周期
  16. 简单脱壳教程笔记(2)---手脱UPX壳(1)
  17. 2 Tables and Table Clusters读书笔记
  18. 微服务入门|微服务架构怎么设计
  19. html如何大小写转换键,怎么把26键变成大写 26键拼音小写怎么转换大写?
  20. 关于“放假”、“休息” “调休” 的各种说法!

热门文章

  1. Java SPI机制简介
  2. CentOS 下安装 Nginx
  3. css div 绝对定位到底部不居中问题
  4. iOS上应用Static Framework
  5. Redis笔记 -- 链表和链表节点的API函数(三)
  6. 网站屏蔽搜索引擎的方法
  7. 编程题目:PAT 1006. 换个格式输出整数 (15)
  8. 基于visual Studio2013解决C语言竞赛题之1030计算函数
  9. 拓端tecdat|Python贝叶斯回归分析住房负担能力数据集
  10. 拓端tecdat|基于出租车GPS轨迹数据的研究:出租车行程的数据分析