批處理框架 Spring Batch 這么強(qiáng)治泥,你會(huì)用嗎梗顺?

spring batch簡(jiǎn)介

spring batch是spring提供的一個(gè)數(shù)據(jù)處理框架。企業(yè)域中的許多應(yīng)用程序需要批量處理才能在關(guān)鍵任務(wù)環(huán)境中執(zhí)行業(yè)務(wù)操作车摄。這些業(yè)務(wù)運(yùn)營(yíng)包括:

無需用戶交互即可最有效地處理大量信息的自動(dòng)化,復(fù)雜處理仑鸥。這些操作通常包括基于時(shí)間的事件(例如月末計(jì)算吮播,通知或通信)。

在非常大的數(shù)據(jù)集中重復(fù)處理復(fù)雜業(yè)務(wù)規(guī)則的定期應(yīng)用(例如眼俊,保險(xiǎn)利益確定或費(fèi)率調(diào)整)意狠。

集成從內(nèi)部和外部系統(tǒng)接收的信息,這些信息通常需要以事務(wù)方式格式化疮胖,驗(yàn)證和處理到記錄系統(tǒng)中环戈。批處理用于每天為企業(yè)處理數(shù)十億的交易。

Spring Batch是一個(gè)輕量級(jí)澎灸,全面的批處理框架院塞,旨在開發(fā)對(duì)企業(yè)系統(tǒng)日常運(yùn)營(yíng)至關(guān)重要的強(qiáng)大批處理應(yīng)用程序。Spring Batch構(gòu)建了人們期望的Spring Framework特性(生產(chǎn)力性昭,基于POJO的開發(fā)方法和一般易用性)拦止,同時(shí)使開發(fā)人員可以在必要時(shí)輕松訪問和利用更高級(jí)的企業(yè)服務(wù)。Spring Batch不是一個(gè)schuedling的框架糜颠。

Spring Batch提供了可重用的功能汹族,這些功能對(duì)于處理大量的數(shù)據(jù)至關(guān)重要,包括記錄/跟蹤其兴,事務(wù)管理顶瞒,作業(yè)處理統(tǒng)計(jì),作業(yè)重啟元旬,跳過和資源管理榴徐。它還提供更高級(jí)的技術(shù)服務(wù)和功能,通過優(yōu)化和分區(qū)技術(shù)實(shí)現(xiàn)極高容量和高性能的批處理作業(yè)法绵。

Spring Batch可用于兩種簡(jiǎn)單的用例(例如將文件讀入數(shù)據(jù)庫(kù)或運(yùn)行存儲(chǔ)過程)以及復(fù)雜的大量用例(例如在數(shù)據(jù)庫(kù)之間移動(dòng)大量數(shù)據(jù)箕速,轉(zhuǎn)換它等等) 上)。大批量批處理作業(yè)可以高度可擴(kuò)展的方式利用該框架來處理大量信息朋譬。

Spring Batch架構(gòu)介紹

一個(gè)典型的批處理應(yīng)用程序大致如下:

從數(shù)據(jù)庫(kù)盐茎,文件或隊(duì)列中讀取大量記錄。

以某種方式處理數(shù)據(jù)徙赢。

以修改之后的形式寫回?cái)?shù)據(jù)字柠。

其對(duì)應(yīng)的示意圖如下:

image.png

spring batch的一個(gè)總體的架構(gòu)如下:

image.png

在spring batch中一個(gè)job可以定義很多的步驟step探越,在每一個(gè)step里面可以定義其專屬的ItemReader用于讀取數(shù)據(jù),ItemProcesseor用于處理數(shù)據(jù)窑业,ItemWriter用于寫數(shù)據(jù)钦幔,而每一個(gè)定義的job則都在JobRepository里面,我們可以通過JobLauncher來啟動(dòng)某一個(gè)job常柄。

Spring Batch核心概念介紹

下面是一些概念是Spring batch框架中的核心概念鲤氢。

什么是Job

Job和Step是spring batch執(zhí)行批處理任務(wù)最為核心的兩個(gè)概念。

其中Job是一個(gè)封裝整個(gè)批處理過程的一個(gè)概念西潘。Job在spring batch的體系當(dāng)中只是一個(gè)最頂層的一個(gè)抽象概念卷玉,體現(xiàn)在代碼當(dāng)中則它只是一個(gè)最上層的接口,其代碼如下:

/**

* Batch domain object representing a job. Job is an explicit abstraction

* representing the configuration of a job specified by a developer. It should

* be noted that restart policy is applied to the job as a whole and not to a

* step.

*/publicinterfaceJob{StringgetName();booleanisRestartable();voidexecute(JobExecutionexecution);JobParametersIncrementergetJobParametersIncrementer();JobParametersValidatorgetJobParametersValidator();}

在Job這個(gè)接口當(dāng)中定義了五個(gè)方法喷市,它的實(shí)現(xiàn)類主要有兩種類型的job相种,一個(gè)是simplejob,另一個(gè)是flowjob品姓。在spring batch當(dāng)中寝并,job是最頂層的抽象,除job之外我們還有JobInstance以及JobExecution這兩個(gè)更加底層的抽象腹备。

一個(gè)job是我們運(yùn)行的基本單位衬潦,它內(nèi)部由step組成。job本質(zhì)上可以看成step的一個(gè)容器馏谨。一個(gè)job可以按照指定的邏輯順序組合step别渔,并提供了我們給所有step設(shè)置相同屬性的方法,例如一些事件監(jiān)聽惧互,跳過策略哎媚。

Spring Batch以SimpleJob類的形式提供了Job接口的默認(rèn)簡(jiǎn)單實(shí)現(xiàn),它在Job之上創(chuàng)建了一些標(biāo)準(zhǔn)功能喊儡。一個(gè)使用java config的例子代碼如下:

@Beanpublic JobfootballJob(){return this.jobBuilderFactory.get("footballJob").start(playerLoad()).next(gameLoad()).next(playerSummarization()).end().build();}

這個(gè)配置的意思是:首先給這個(gè)job起了一個(gè)名字叫footballJob拨与,接著指定了這個(gè)job的三個(gè)step,他們分別由方法艾猜,playerLoad,gameLoad, playerSummarization實(shí)現(xiàn)买喧。

什么是JobInstance

我們?cè)谏衔囊呀?jīng)提到了JobInstance,他是Job的更加底層的一個(gè)抽象匆赃,他的定義如下:

publicinterfaceJobInstance{/**

? * Get unique id for this JobInstance.

? * @return instance id

? */publiclonggetInstanceId();/**

? * Get job name.

? * @return value of 'id' attribute from <job>

? */publicStringgetJobName();}

他的方法很簡(jiǎn)單淤毛,一個(gè)是返回Job的id,另一個(gè)是返回Job的名字算柳。

JobInstance指的是job運(yùn)行當(dāng)中低淡,作業(yè)執(zhí)行過程當(dāng)中的概念。Instance本就是實(shí)例的意思。

比如說現(xiàn)在有一個(gè)批處理的job蔗蹋,它的功能是在一天結(jié)束時(shí)執(zhí)行行一次何荚。我們假定這個(gè)批處理job的名字為'EndOfDay'。在這個(gè)情況下猪杭,那么每天就會(huì)有一個(gè)邏輯意義上的JobInstance, 而我們必須記錄job的每次運(yùn)行的情況餐塘。

什么是JobParameters

在上文當(dāng)中我們提到了,同一個(gè)job每天運(yùn)行一次的話皂吮,那么每天都有一個(gè)jobIntsance戒傻,但他們的job定義都是一樣的,那么我們?cè)趺磥韰^(qū)別一個(gè)job的不同jobinstance了蜂筹。不妨先做個(gè)猜想稠鼻,雖然jobinstance的job定義一樣,但是他們有的東西就不一樣狂票,例如運(yùn)行時(shí)間。

spring batch中提供的用來標(biāo)識(shí)一個(gè)jobinstance的東西是:JobParameters熙暴。JobParameters對(duì)象包含一組用于啟動(dòng)批處理作業(yè)的參數(shù)闺属,它可以在運(yùn)行期間用于識(shí)別或甚至用作參考數(shù)據(jù)。我們假設(shè)的運(yùn)行時(shí)間周霉,就可以作為一個(gè)JobParameters掂器。

例如, 我們前面的'EndOfDay'的job現(xiàn)在已經(jīng)有了兩個(gè)實(shí)例,一個(gè)產(chǎn)生于1月1日俱箱,另一個(gè)產(chǎn)生于1月2日国瓮,那么我們就可以定義兩個(gè)JobParameter對(duì)象:一個(gè)的參數(shù)是01-01, 另一個(gè)的參數(shù)是01-02。因此狞谱,識(shí)別一個(gè)JobInstance的方法可以定義為:

image.png

因此乃摹,我么可以通過Jobparameter來操作正確的JobInstance

什么是JobExecution

JobExecution指的是單次嘗試運(yùn)行一個(gè)我們定義好的Job的代碼層面的概念。job的一次執(zhí)行可能以失敗也可能成功跟衅。只有當(dāng)執(zhí)行成功完成時(shí)孵睬,給定的與執(zhí)行相對(duì)應(yīng)的JobInstance才也被視為完成。

還是以前面描述的EndOfDay的job作為示例伶跷,假設(shè)第一次運(yùn)行01-01-2019的JobInstance結(jié)果是失敗掰读。那么此時(shí)如果使用與第一次運(yùn)行相同的Jobparameter參數(shù)(即01-01-2019)作業(yè)參數(shù)再次運(yùn)行,那么就會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)于之前jobInstance的一個(gè)新的JobExecution實(shí)例,JobInstance仍然只有一個(gè)叭莫。

JobExecution的接口定義如下:

publicinterfaceJobExecution{/**

? * Get unique id for this JobExecution.

? * @return execution id

? */publiclonggetExecutionId();/**

? * Get job name.

? * @return value of 'id' attribute from <job>

? */publicStringgetJobName();/**

? * Get batch status of this execution.

? * @return batch status value.

? */publicBatchStatusgetBatchStatus();/**

? * Get time execution entered STARTED status.

? * @return date (time)

? */publicDategetStartTime();/**

? * Get time execution entered end status: COMPLETED, STOPPED, FAILED

? * @return date (time)

? */publicDategetEndTime();/**

? * Get execution exit status.

? * @return exit status.

? */publicStringgetExitStatus();/**

? * Get time execution was created.

? * @return date (time)

? */publicDategetCreateTime();/**

? * Get time execution was last updated updated.

? * @return date (time)

? */publicDategetLastUpdatedTime();/**

? * Get job parameters for this execution.

? * @return job parameters?

? */publicPropertiesgetJobParameters();}

每一個(gè)方法的注釋已經(jīng)解釋的很清楚蹈集,這里不再多做解釋。只提一下BatchStatus雇初,JobExecution當(dāng)中提供了一個(gè)方法getBatchStatus用于獲取一個(gè)job某一次特地執(zhí)行的一個(gè)狀態(tài)拢肆。BatchStatus是一個(gè)代表job狀態(tài)的枚舉類,其定義如下:

publicenumBatchStatus{STARTING,STARTED,STOPPING,STOPPED,FAILED,COMPLETED,ABANDONED}

這些屬性對(duì)于一個(gè)job的執(zhí)行來說是非常關(guān)鍵的信息,并且spring batch會(huì)將他們持久到數(shù)據(jù)庫(kù)當(dāng)中. 在使用Spring batch的過程當(dāng)中spring batch會(huì)自動(dòng)創(chuàng)建一些表用于存儲(chǔ)一些job相關(guān)的信息善榛,用于存儲(chǔ)JobExecution的表為batch_job_execution,下面是一個(gè)從數(shù)據(jù)庫(kù)當(dāng)中截圖的實(shí)例:

image.png

什么是Step

每一個(gè)Step對(duì)象都封裝了批處理作業(yè)的一個(gè)獨(dú)立的階段辩蛋。事實(shí)上童太,每一個(gè)Job本質(zhì)上都是由一個(gè)或多個(gè)步驟組成菇夸。每一個(gè)step包含定義和控制實(shí)際批處理所需的所有信息。任何特定的內(nèi)容都由編寫Job的開發(fā)人員自行決定袱耽。

一個(gè)step可以非常簡(jiǎn)單也可以非常復(fù)雜咒循。例如据途,一個(gè)step的功能是將文件中的數(shù)據(jù)加載到數(shù)據(jù)庫(kù)中,那么基于現(xiàn)在spring batch的支持則幾乎不需要寫代碼叙甸。更復(fù)雜的step可能具有復(fù)雜的業(yè)務(wù)邏輯颖医,這些邏輯作為處理的一部分。

與Job一樣裆蒸,Step具有與JobExecution類似的StepExecution熔萧,如下圖所示:

image.png

什么是StepExecution

StepExecution表示一次執(zhí)行Step, 每次運(yùn)行一個(gè)Step時(shí)都會(huì)創(chuàng)建一個(gè)新的StepExecution,類似于JobExecution僚祷。但是佛致,某個(gè)步驟可能由于其之前的步驟失敗而無法執(zhí)行。且僅當(dāng)Step實(shí)際啟動(dòng)時(shí)才會(huì)創(chuàng)建StepExecution辙谜。

一次step執(zhí)行的實(shí)例由StepExecution類的對(duì)象表示俺榆。每個(gè)StepExecution都包含對(duì)其相應(yīng)步驟的引用以及JobExecution和事務(wù)相關(guān)的數(shù)據(jù),例如提交和回滾計(jì)數(shù)以及開始和結(jié)束時(shí)間装哆。

此外罐脊,每個(gè)步驟執(zhí)行都包含一個(gè)ExecutionContext,其中包含開發(fā)人員需要在批處理運(yùn)行中保留的任何數(shù)據(jù)蜕琴,例如重新啟動(dòng)所需的統(tǒng)計(jì)信息或狀態(tài)信息萍桌。下面是一個(gè)從數(shù)據(jù)庫(kù)當(dāng)中截圖的實(shí)例:

image.png

什么是ExecutionContext

ExecutionContext即每一個(gè)StepExecution 的執(zhí)行環(huán)境。它包含一系列的鍵值對(duì)凌简。我們可以用如下代碼獲取ExecutionContext

ExecutionContext ecStep = stepExecution.getExecutionContext();ExecutionContext ecJob = jobExecution.getExecutionContext();

什么是JobRepository

JobRepository是一個(gè)用于將上述job梗夸,step等概念進(jìn)行持久化的一個(gè)類。它同時(shí)給Job和Step以及下文會(huì)提到的JobLauncher實(shí)現(xiàn)提供CRUD操作号醉。

首次啟動(dòng)Job時(shí)反症,將從repository中獲取JobExecution,并且在執(zhí)行批處理的過程中畔派,StepExecution和JobExecution將被存儲(chǔ)到repository當(dāng)中铅碍。

@EnableBatchProcessing注解可以為JobRepository提供自動(dòng)配置。

什么是JobLauncher

JobLauncher這個(gè)接口的功能非常簡(jiǎn)單线椰,它是用于啟動(dòng)指定了JobParameters的Job胞谈,為什么這里要強(qiáng)調(diào)指定了JobParameter,原因其實(shí)我們?cè)谇懊嬉呀?jīng)提到了,jobparameter和job一起才能組成一次job的執(zhí)行烦绳。下面是代碼實(shí)例:

publicinterfaceJobLauncher{publicJobExecutionrun(Jobjob,JobParametersjobParameters)throwsJobExecutionAlreadyRunningException,JobRestartException,JobInstanceAlreadyCompleteException,JobParametersInvalidException;}

上面run方法實(shí)現(xiàn)的功能是根據(jù)傳入的job以及jobparamaters從JobRepository獲取一個(gè)JobExecution并執(zhí)行Job卿捎。

什么是Item Reader

ItemReader是一個(gè)讀數(shù)據(jù)的抽象,它的功能是為每一個(gè)Step提供數(shù)據(jù)輸入径密。當(dāng)ItemReader以及讀完所有數(shù)據(jù)時(shí)午阵,它會(huì)返回null來告訴后續(xù)操作數(shù)據(jù)已經(jīng)讀完。Spring Batch為ItemReader提供了非常多的有用的實(shí)現(xiàn)類享扔,比如JdbcPagingItemReader底桂,JdbcCursorItemReader等等。

ItemReader支持的讀入的數(shù)據(jù)源也是非常豐富的惧眠,包括各種類型的數(shù)據(jù)庫(kù)籽懦,文件,數(shù)據(jù)流氛魁,等等暮顺。幾乎涵蓋了我們的所有場(chǎng)景。

下面是一個(gè)JdbcPagingItemReader的例子代碼:

@BeanpublicJdbcPagingItemReaderitemReader(DataSourcedataSource,PagingQueryProviderqueryProvider){Map<String,Object>parameterValues=newHashMap<>();parameterValues.put("status","NEW");returnnewJdbcPagingItemReaderBuilder<CustomerCredit>().name("creditReader").dataSource(dataSource).queryProvider(queryProvider).parameterValues(parameterValues).rowMapper(customerCreditMapper()).pageSize(1000).build();}@BeanpublicSqlPagingQueryProviderFactoryBeanqueryProvider(){SqlPagingQueryProviderFactoryBeanprovider=newSqlPagingQueryProviderFactoryBean();provider.setSelectClause("select id, name, credit");provider.setFromClause("from customer");provider.setWhereClause("where status=:status");provider.setSortKey("id");returnprovider;}

JdbcPagingItemReader必須指定一個(gè)PagingQueryProvider秀存,負(fù)責(zé)提供SQL查詢語(yǔ)句來按分頁(yè)返回?cái)?shù)據(jù)拖云。

下面是一個(gè)JdbcCursorItemReader的例子代碼:

private JdbcCursorItemReader<Map<String,Object>>buildItemReader(finalDataSource dataSource,String tableName,String tenant){JdbcCursorItemReader<Map<String,Object>>itemReader=newJdbcCursorItemReader<>();itemReader.setDataSource(dataSource);itemReader.setSql("sql here");itemReader.setRowMapper(newRowMapper());returnitemReader;}

什么是Item Writer

既然ItemReader是讀數(shù)據(jù)的一個(gè)抽象,那么ItemWriter自然就是一個(gè)寫數(shù)據(jù)的抽象应又,它是為每一個(gè)step提供數(shù)據(jù)寫出的功能。寫的單位是可以配置的乏苦,我們可以一次寫一條數(shù)據(jù)株扛,也可以一次寫一個(gè)chunk的數(shù)據(jù),關(guān)于chunk下文會(huì)有專門的介紹汇荐。ItemWriter對(duì)于讀入的數(shù)據(jù)是不能做任何操作的洞就。

Spring Batch為ItemWriter也提供了非常多的有用的實(shí)現(xiàn)類,當(dāng)然我們也可以去實(shí)現(xiàn)自己的writer功能掀淘。

什么是Item Processor

ItemProcessor對(duì)項(xiàng)目的業(yè)務(wù)邏輯處理的一個(gè)抽象, 當(dāng)ItemReader讀取到一條記錄之后旬蟋,ItemWriter還未寫入這條記錄之前,I我們可以借助temProcessor提供一個(gè)處理業(yè)務(wù)邏輯的功能革娄,并對(duì)數(shù)據(jù)進(jìn)行相應(yīng)操作倾贰。如果我們?cè)贗temProcessor發(fā)現(xiàn)一條數(shù)據(jù)不應(yīng)該被寫入,可以通過返回null來表示拦惋。ItemProcessor和ItemReader以及ItemWriter可以非常好的結(jié)合在一起工作匆浙,他們之間的數(shù)據(jù)傳輸也非常方便。我們直接使用即可厕妖。

chunk 處理流程

spring batch提供了讓我們按照chunk處理數(shù)據(jù)的能力首尼,一個(gè)chunk的示意圖如下:

image.png

它的意思就和圖示的一樣,由于我們一次batch的任務(wù)可能會(huì)有很多的數(shù)據(jù)讀寫操作,因此一條一條的處理并向數(shù)據(jù)庫(kù)提交的話效率不會(huì)很高软能,因此spring batch提供了chunk這個(gè)概念迎捺,我們可以設(shè)定一個(gè)chunk size,spring batch 將一條一條處理數(shù)據(jù)查排,但不提交到數(shù)據(jù)庫(kù)凳枝,只有當(dāng)處理的數(shù)據(jù)數(shù)量達(dá)到chunk size設(shè)定的值得時(shí)候,才一起去commit.

java的實(shí)例定義代碼如下:

image.png

在上面這個(gè)step里面雹嗦,chunk size被設(shè)為了10范舀,當(dāng)ItemReader讀的數(shù)據(jù)數(shù)量達(dá)到10的時(shí)候,這一批次的數(shù)據(jù)就一起被傳到itemWriter了罪,同時(shí)transaction被提交锭环。

skip策略和失敗處理

一個(gè)batch的job的step,可能會(huì)處理非常大數(shù)量的數(shù)據(jù)泊藕,難免會(huì)遇到出錯(cuò)的情況辅辩,出錯(cuò)的情況雖出現(xiàn)的概率較小,但是我們不得不考慮這些情況娃圆,因?yàn)槲覀冏鰯?shù)據(jù)遷移最重要的是要保證數(shù)據(jù)的最終一致性玫锋。spring batch當(dāng)然也考慮到了這種情況,并且為我們提供了相關(guān)的技術(shù)支持讼呢,請(qǐng)看如下bean的配置:

image.png

我們需要留意這三個(gè)方法撩鹿,分別是skipLimit(),skip(),noSkip(),

skipLimit方法的意思是我們可以設(shè)定一個(gè)我們?cè)试S的這個(gè)step可以跳過的異常數(shù)量,假如我們?cè)O(shè)定為10悦屏,則當(dāng)這個(gè)step運(yùn)行時(shí)节沦,只要出現(xiàn)的異常數(shù)目不超過10,整個(gè)step都不會(huì)fail础爬。注意甫贯,若不設(shè)定skipLimit,則其默認(rèn)值是0.

skip方法我們可以指定我們可以跳過的異常看蚜,因?yàn)橛行┊惓5某霈F(xiàn)叫搁,我們是可以忽略的。

noSkip方法的意思則是指出現(xiàn)這個(gè)異常我們不想跳過供炎,也就是從skip的所以exception當(dāng)中排除這個(gè)exception渴逻,從上面的例子來說,也就是跳過所有除FileNotFoundException的exception音诫。

那么對(duì)于這個(gè)step來說裸卫,F(xiàn)ileNotFoundException就是一個(gè)fatal的exception,拋出這個(gè)exception的時(shí)候step就會(huì)直接fail

批處理操作指南

本部分是一些使用spring batch時(shí)的值得注意的點(diǎn)

批處理原則

在構(gòu)建批處理解決方案時(shí)纽竣,應(yīng)考慮以下關(guān)鍵原則和注意事項(xiàng)墓贿。

批處理體系結(jié)構(gòu)通常會(huì)影響體系結(jié)構(gòu)

盡可能簡(jiǎn)化并避免在單批應(yīng)用程序中構(gòu)建復(fù)雜的邏輯結(jié)構(gòu)

保持?jǐn)?shù)據(jù)的處理和存儲(chǔ)在物理上靠得很近(換句話說茧泪,將數(shù)據(jù)保存在處理過程中)。

最大限度地減少系統(tǒng)資源的使用聋袋,尤其是I / O. 在internal memory中執(zhí)行盡可能多的操作队伟。

查看應(yīng)用程序I / O(分析SQL語(yǔ)句)以確保避免不必要的物理I / O. 特別是,需要尋找以下四個(gè)常見缺陷:

當(dāng)數(shù)據(jù)可以被讀取一次并緩存或保存在工作存儲(chǔ)中時(shí)幽勒,讀取每個(gè)事務(wù)的數(shù)據(jù)嗜侮。

重新讀取先前在同一事務(wù)中讀取數(shù)據(jù)的事務(wù)的數(shù)據(jù)。

導(dǎo)致不必要的表或索引掃描啥容。

未在SQL語(yǔ)句的WHERE子句中指定鍵值锈颗。

在批處理運(yùn)行中不要做兩次一樣的事情。例如咪惠,如果需要數(shù)據(jù)匯總以用于報(bào)告目的击吱,則應(yīng)該(如果可能)在最初處理數(shù)據(jù)時(shí)遞增存儲(chǔ)的總計(jì),因此您的報(bào)告應(yīng)用程序不必重新處理相同的數(shù)據(jù)遥昧。

在批處理應(yīng)用程序開始時(shí)分配足夠的內(nèi)存覆醇,以避免在此過程中進(jìn)行耗時(shí)的重新分配。

總是假設(shè)數(shù)據(jù)完整性最差炭臭。插入適當(dāng)?shù)臋z查和記錄驗(yàn)證以維護(hù)數(shù)據(jù)完整性永脓。

盡可能實(shí)施校驗(yàn)和以進(jìn)行內(nèi)部驗(yàn)證。例如鞋仍,對(duì)于一個(gè)文件里的數(shù)據(jù)應(yīng)該有一個(gè)數(shù)據(jù)條數(shù)紀(jì)錄常摧,告訴文件中的記錄總數(shù)以及關(guān)鍵字段的匯總。

在具有真實(shí)數(shù)據(jù)量的類似生產(chǎn)環(huán)境中盡早計(jì)劃和執(zhí)行壓力測(cè)試威创。

在大批量系統(tǒng)中落午,數(shù)據(jù)備份可能具有挑戰(zhàn)性,特別是如果系統(tǒng)以24-7在線的情況運(yùn)行那婉。數(shù)據(jù)庫(kù)備份通常在在線設(shè)計(jì)中得到很好的處理,但文件備份應(yīng)該被視為同樣重要党瓮。如果系統(tǒng)依賴于文件详炬,則文件備份過程不僅應(yīng)該到位并記錄在案,還應(yīng)定期進(jìn)行測(cè)試寞奸。

如何默認(rèn)不啟動(dòng)job

在使用java config使用spring batch的job時(shí)呛谜,如果不做任何配置,項(xiàng)目在啟動(dòng)時(shí)就會(huì)默認(rèn)去跑我們定義好的批處理job枪萄。那么如何讓項(xiàng)目在啟動(dòng)時(shí)不自動(dòng)去跑job呢隐岛?

spring batch的job會(huì)在項(xiàng)目啟動(dòng)時(shí)自動(dòng)run,如果我們不想讓他在啟動(dòng)時(shí)run的話瓷翻,可以在application.properties中添加如下屬性:

spring.batch.job.enabled=false

在讀數(shù)據(jù)時(shí)內(nèi)存不夠

在使用spring batch做數(shù)據(jù)遷移時(shí)聚凹,發(fā)現(xiàn)在job啟動(dòng)后割坠,執(zhí)行到一定時(shí)間點(diǎn)時(shí)就卡在一個(gè)地方不動(dòng)了,且log也不再打印妒牙,等待一段時(shí)間之后彼哼,得到如下錯(cuò)誤:

image.png

紅字的信息為:Resource exhaustion event:the JVM was unable to allocate memory from the heap.

翻譯過來的意思就是項(xiàng)目發(fā)出了一個(gè)資源耗盡的事件,告訴我們java虛擬機(jī)無法再為堆分配內(nèi)存湘今。

造成這個(gè)錯(cuò)誤的原因是: 這個(gè)項(xiàng)目里的batch job的reader是一次性拿回了數(shù)據(jù)庫(kù)里的所有數(shù)據(jù)敢朱,并沒有進(jìn)行分頁(yè),當(dāng)這個(gè)數(shù)據(jù)量太大時(shí)摩瞎,就會(huì)導(dǎo)致內(nèi)存不夠用拴签。解決的辦法有兩個(gè):

調(diào)整reader讀數(shù)據(jù)邏輯,按分頁(yè)讀取旗们,但實(shí)現(xiàn)上會(huì)麻煩一些蚓哩,且運(yùn)行效率會(huì)下降

增大service內(nèi)存

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蚪拦,隨后出現(xiàn)的幾起案子杖剪,更是在濱河造成了極大的恐慌,老刑警劉巖驰贷,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盛嘿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡括袒,警方通過查閱死者的電腦和手機(jī)次兆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锹锰,“玉大人芥炭,你說我怎么就攤上這事∈鸦郏” “怎么了园蝠?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)痢士。 經(jīng)常有香客問我彪薛,道長(zhǎng),這世上最難降的妖魔是什么怠蹂? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任善延,我火速辦了婚禮,結(jié)果婚禮上城侧,老公的妹妹穿的比我還像新娘易遣。我一直安慰自己,他們只是感情好嫌佑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布豆茫。 她就那樣靜靜地躺著侨歉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪澜薄。 梳的紋絲不亂的頭發(fā)上为肮,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音肤京,去河邊找鬼颊艳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛忘分,可吹牛的內(nèi)容都是我干的棋枕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼妒峦,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼重斑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起肯骇,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤窥浪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后笛丙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漾脂,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年胚鸯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了骨稿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡姜钳,死狀恐怖坦冠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哥桥,我是刑警寧澤辙浑,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站拟糕,受9級(jí)特大地震影響判呕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜已卸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一佛玄、第九天 我趴在偏房一處隱蔽的房頂上張望硼一。 院中可真熱鬧累澡,春花似錦、人聲如沸般贼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蕊梧,卻和暖如春霞赫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肥矢。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工端衰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人甘改。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓旅东,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親十艾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子抵代,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容