网易首页 > 网易号 > 正文 申请入驻

【090期】批处理框架 Spring Batch,数据迁移量过大如何保证内存?

0
分享至

点击上方“Java精选”,选择“设为星标”

别问别人为什么,多问自己凭什么!

下方留言必回,有问必答!

每天 08:00 更新文章,每天进步一点点...

概述

本篇博客是记录使用spring batch做数据迁移时时遇到的一个关键问题:数据迁移量大时如何保证内存。当我们在使用spring batch时,我们必须配置三个东西: reader,processor,和writer。

其中,reader用于从数据库中读数据,当数据量较小时,reader的逻辑不会对内存带来太多压力,但是当我们要去读的数据量非常大的时候,我们就不得不考虑内存等方面的问题,因为若数据量非常大,内存,执行时间等等都会受到影响。关于spring batch的基础知识和介绍请参考这篇博客:批处理框架 Spring Batch 这么强,你会用吗?

https://blog.csdn.net/afreon/article/details/118384238
问题是什么?

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

在学习了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来读取数据。推荐公众号Java精选,回复Java面试,在线刷面试题。

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是必要的。但同时,因为要实现分页,也会带来一些不可避免的限制。

作者:topEngineerray blog.csdn.net/topdeveloperr/article/details/88843186

期往精选 点击标题可跳转

- 小程序,3000+ 道面试题在线刷,最新、最全 Java 面试题!

文章有帮助的话,在看,转发吧!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
朱珠晒意大利一家三口出游照,画面满是温馨幸福感,5岁女儿近照曝光

朱珠晒意大利一家三口出游照,画面满是温馨幸福感,5岁女儿近照曝光

生性洒脱
2026-07-04 10:54:10
26届高考生狂喜吧!截至目前,今年高考已有6个好消息!重点了解

26届高考生狂喜吧!截至目前,今年高考已有6个好消息!重点了解

糖逗在娱乐
2026-07-04 21:04:19
中国男篮只带12人出征韩国:战中国台北成生死战 剩9人回北京训练

中国男篮只带12人出征韩国:战中国台北成生死战 剩9人回北京训练

醉卧浮生
2026-07-04 11:31:59
心理学:如果一个人对家人一点就炸、说话不留情,对外人却稳重克制、彬彬有礼,不是双面性格,根源追下来就是这两个字

心理学:如果一个人对家人一点就炸、说话不留情,对外人却稳重克制、彬彬有礼,不是双面性格,根源追下来就是这两个字

心理观察局
2026-07-04 06:41:19
心理学:“人没出息,一看便知”:没出息的人,多半喜欢做这两件事,很准

心理学:“人没出息,一看便知”:没出息的人,多半喜欢做这两件事,很准

心理观察局
2026-07-04 07:13:03
全队痛哭!54万人口岛国站着死:逼疯阿根廷+踢平西班牙 将踢国足

全队痛哭!54万人口岛国站着死:逼疯阿根廷+踢平西班牙 将踢国足

风过乡
2026-07-04 09:11:43
中国44年来首次试射洲际导弹,全球反应堪比好莱坞大片

中国44年来首次试射洲际导弹,全球反应堪比好莱坞大片

烽火三月佳人三千
2026-06-25 14:21:42
佛得角后卫卡布拉尔:我不敢相信自己能进个这么精彩的球

佛得角后卫卡布拉尔:我不敢相信自己能进个这么精彩的球

懂球帝
2026-07-04 16:08:33
赖清德四个台独动作,叫板大陆,郑丽文急忙喊话,大陆军警再出手

赖清德四个台独动作,叫板大陆,郑丽文急忙喊话,大陆军警再出手

共工之锚
2026-07-05 00:02:29
湖北一大妈跳了20多年广场舞后,拿100多个金镯子去卖,说家里还有金项链没拿,我人好,都是别人送的

湖北一大妈跳了20多年广场舞后,拿100多个金镯子去卖,说家里还有金项链没拿,我人好,都是别人送的

背包旅行
2026-07-04 11:16:30
2026旅游业现状:“奄奄一息”的商户,甚至没有最后的力气去哀嚎

2026旅游业现状:“奄奄一息”的商户,甚至没有最后的力气去哀嚎

混沌录
2026-07-03 19:56:08
F1英国站排位赛:安东内利杆位,勒克莱尔第二,汉密尔顿第三

F1英国站排位赛:安东内利杆位,勒克莱尔第二,汉密尔顿第三

懂球帝
2026-07-05 00:17:22
飞机上偶遇巨型阿拉斯加,因太胖挤不进座,全舱人看它憋大招!

飞机上偶遇巨型阿拉斯加,因太胖挤不进座,全舱人看它憋大招!

Magic宠物社
2026-07-04 20:35:03
内贾德打破沉默,“反美斗士”要利用穆杰塔巴,东山再起重掌大权

内贾德打破沉默,“反美斗士”要利用穆杰塔巴,东山再起重掌大权

时光流转追梦人
2026-07-04 23:58:43
7月4日:指数分析、比分、加拿大vs摩洛哥、巴拉圭vs法国

7月4日:指数分析、比分、加拿大vs摩洛哥、巴拉圭vs法国

林子说事
2026-07-04 16:28:12
秦海璐变卖房产,清空全部资产,凑出近亿身家,绝境兜底救下刘涛

秦海璐变卖房产,清空全部资产,凑出近亿身家,绝境兜底救下刘涛

秋别离
2026-06-13 15:50:00
杨紫获白玉兰奖后首参线下活动,身后男大佬曝光,难怪能捧成视后

杨紫获白玉兰奖后首参线下活动,身后男大佬曝光,难怪能捧成视后

暖心萌阿菇凉
2026-07-04 23:38:22
武两高速大桥合龙!重庆主城1小时直达武隆

武两高速大桥合龙!重庆主城1小时直达武隆

刘哥谈体育
2026-07-04 19:36:32
贝克汉姆留名星光大道,15岁贝小七美成芭比娃娃!

贝克汉姆留名星光大道,15岁贝小七美成芭比娃娃!

ChicMyGeek
2026-06-14 11:03:06
我一直被领导边缘化,拿到涨薪40%的offer后提了离职,没想到领导说:“其实你挺笨的,之所以一直留着你,是因为你还算听话!”

我一直被领导边缘化,拿到涨薪40%的offer后提了离职,没想到领导说:“其实你挺笨的,之所以一直留着你,是因为你还算听话!”

励职派
2026-07-04 19:15:50
2026-07-05 01:04:49
Java精选
Java精选
一场永远也演不完的戏
1796文章数 3859关注度
往期回顾 全部

科技要闻

韬定律论文V2版,充工程细节和实测数据

头条要闻

老人被一次拔12颗牙种10颗:能刷的钱都刷走 只剩30块

头条要闻

老人被一次拔12颗牙种10颗:能刷的钱都刷走 只剩30块

体育要闻

揭法国锋线最大优势 有人比姆巴佩还快?

娱乐要闻

白鹿打戏抠图惹非议 连累丞磊遭扒皮

财经要闻

韩国股市杠杆失控:450亿美元资金狂飙

汽车要闻

方程豹钛9内饰曝光 用上了长联屏设计/下半年上市

态度原创

家居
数码
本地
时尚
公开课

家居要闻

传奇筑 日常诗

数码要闻

苏姿丰签名同款!极摩客EVO-X3 AI工作站全球开卖:国行版21699元起

本地新闻

国内足球之旅?这座小城给你高分答案

别再说"露肩衣服 "难驾驭!看看这几组日常穿搭,大方有回头率

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版