Spring Batch 3 - Job異常處理

上篇文章中这橙,我們了解了讀文件寫數(shù)據(jù)庫的流程。這里我們假設(shè)导披,日志文件在某一行的數(shù)據(jù)異常屈扎,比如逗號(hào)分隔后不是5部分,而變成了6部分撩匕,當(dāng)程序執(zhí)行到此行時(shí)就會(huì)拋出 FlatFileParseException 異常鹰晨,Job停止執(zhí)行。我們可以從兩部分解決這個(gè)問題如果我們想讓程序忽略這種異常滑沧,可以修改Job的配置方式如下:并村。

以下場景都是基于Spring Batch 3 - 讀文件寫數(shù)據(jù)庫這篇文件巍实。

忽略異常

有些情況下滓技,我們想讓程序忽略掉這種異常,修改Job配置如下:

    <batch:job id="readFile2DBJob">
        <batch:step id="readFile2DBStep">
            <batch:tasklet>
                <batch:chunk reader="logReader" writer="mysqlItemWriter" commit-interval="1000" skip-limit="2000">
                    <!-- 發(fā)生這些異常時(shí)棚潦,直接跳過繼續(xù)處理,skippable-exception-classes必須要配合skip-limit屬性使用 -->
                    <batch:skippable-exception-classes>
                        <batch:include class="org.springframework.batch.item.file.FlatFileParseException"/>
                    </batch:skippable-exception-classes>
                </batch:chunk>
            </batch:tasklet>
        </batch:step>
    </batch:job>

skip-limit="2000" 指可以忽略的最大次數(shù)(行數(shù))令漂,如果你不知道你有都少個(gè)異常數(shù)據(jù),想全部忽略掉丸边,就盡量配置的大點(diǎn)

Job重新執(zhí)行

另外的情況叠必,出錯(cuò)時(shí)讓程序停止,通過手工或其它方式糾正錯(cuò)誤后妹窖,讓程序繼續(xù)執(zhí)行纬朝。當(dāng)然,比如我們處理到2051行錯(cuò)誤時(shí)骄呼,糾正錯(cuò)誤數(shù)據(jù)后共苛,我們希望Job能繼續(xù)從上次失敗的行繼續(xù)開始處理,而不是從第1行從頭再來蜓萄。 這就是Spring Batch的優(yōu)勢隅茎,它會(huì)自動(dòng)記錄你上次執(zhí)行成功的地址,再次執(zhí)行此job時(shí)會(huì)從這里繼續(xù)出來嫉沽。

我們來實(shí)際模擬下辟犀,假設(shè)我們在2051行的數(shù)據(jù)為:

2016-11-18 13:31:53,/test/user/user_visit/saveVisitStep,gz_qinrong,3,/test/3.201610171_1/Android,/5.1.1/Mi-4c/4faccbe5-bb26-4a0c-94aa-d9e0805f6367

注意在Android后面多加了一個(gè)逗號(hào),導(dǎo)致此行逗號(hào)分隔后有6部分绸硕,而不是正常的5部分

執(zhí)行job時(shí)我們會(huì)發(fā)生如下異常:

org.springframework.batch.item.file.FlatFileParseException: Parsing error at line: 2051 in resource=[URL [file:/my/access.log]], input=[2016-11-18 13:31:53,/test/user/user_visit/saveVisitStep,gz_qinrong,3,/test/3.201610171_1/Android,/5.1.1/Mi-4c/4faccbe5-bb26-4a0c-94aa-d9e0805f6367]
 at org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:183)
 at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.read(AbstractItemCountingItemStreamItemReader.java:88)
 at org.springframework.batch.core.step.item.SimpleChunkProvider.doRead(SimpleChunkProvider.java:91)
 at org.springframework.batch.core.step.item.SimpleChunkProvider.read(SimpleChunkProvider.java:157)
 at org.springframework.batch.core.step.item.SimpleChunkProvider$1.doInIteration(SimpleChunkProvider.java:116)
 at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374)
 at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
 at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
 at org.springframework.batch.core.step.item.SimpleChunkProvider.provide(SimpleChunkProvider.java:110)
 at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:69)
 at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406)
 at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330)
 at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
 at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:271)
 at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81)
 at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374)
 at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
 at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
 at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
 at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200)
 at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
 at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:64)
 at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67)
 at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169)
 at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144)
 at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:134)
 at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306)
 at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135)
 at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
 at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128)
 at com.me.springbatch.App.run(App.java:27)
 at com.me.springbatch.file2db.File2DBMain.main(File2DBMain.java:9)
Caused by: org.springframework.batch.item.file.transform.IncorrectTokenCountException: Incorrect number of tokens found in record: expected 5 actual 6
 at org.springframework.batch.item.file.transform.AbstractLineTokenizer.tokenize(AbstractLineTokenizer.java:125)
 at org.springframework.batch.item.file.mapping.DefaultLineMapper.mapLine(DefaultLineMapper.java:43)
 at org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:180)
 ... 31 more

Spring Batch 表BATCH_STEP_EXECUTION中的信息如下:

BATCH_STEP_EXECUTION表

從圖上可以看出堂竟,程序讀了2050行魂毁,寫了2000行,提交了2次(我們設(shè)定了commit-interval="1000")跃捣。

如果我們不處理異常數(shù)據(jù)(錯(cuò)誤依舊存在)漱牵,再次執(zhí)行下Job,肯定依舊程序會(huì)報(bào)異常疚漆,表BATCH_STEP_EXECUTION中的信息如下

BATCH_STEP_EXECUTION表

從表中可以看出酣胀。第二行讀到50就異常了,寫了0行娶聘,也就證明了Job是從上次成功的地方(2000行)后開始執(zhí)行的闻镶。

我們手工糾正2051行的數(shù)據(jù),去掉多余的逗號(hào)丸升,再次執(zhí)行铆农,直到Job完全執(zhí)行成功。

日志源文件總共508828行
BATCH_STEP_EXECUTION表
業(yè)務(wù)表

我們可以看到狡耻,業(yè)務(wù)表中的總數(shù)據(jù)量正好=多次執(zhí)行的write_count合計(jì)墩剖。日志文件中的數(shù)據(jù)被完全處理,且未有重復(fù)數(shù)據(jù)夷狰。

總結(jié)

  1. 執(zhí)行時(shí)要把spring-context.xml中的以下配置注釋掉岭皂,否則每次執(zhí)行都重新drop并創(chuàng)建表,也就無法保留上次執(zhí)行的job信息了沼头。
    <!-- 
       初始化腳本爷绘,主要用來創(chuàng)建spring-batch運(yùn)行時(shí)的數(shù)據(jù),應(yīng)用生成環(huán)境時(shí)應(yīng)該去掉此配置进倍,手工創(chuàng)建下對應(yīng)的表 
       spring-batch本身job運(yùn)行需要的表的創(chuàng)建腳本土至,spring-batch.jar中默認(rèn)提供了各種數(shù)據(jù)庫的DDL語句
    
    <jdbc:initialize-database data-source="dataSource">
        <jdbc:script location="${batch.schema.script.drop}" />
        <jdbc:script location="${batch.schema.script}" />
    </jdbc:initialize-database>
-->
  1. 兩次執(zhí)行Job時(shí),JobParameters參數(shù)必須要一樣猾昆,否則Spring Batch會(huì)認(rèn)為兩次執(zhí)行的為不同Job陶因。
  2. 從這里我們就能看出Spring Batch的靈活與強(qiáng)大,后面的章節(jié)我們再看看Spring Batch還有哪些優(yōu)點(diǎn)

附完整代碼

https://git.oschina.net/heichong/spring-batch-demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末垂蜗,一起剝皮案震驚了整個(gè)濱河市楷扬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌么抗,老刑警劉巖毅否,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蝇刀,居然都是意外死亡螟加,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捆探,“玉大人然爆,你說我怎么就攤上這事∈蛲迹” “怎么了曾雕?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長助被。 經(jīng)常有香客問我剖张,道長,這世上最難降的妖魔是什么揩环? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任搔弄,我火速辦了婚禮,結(jié)果婚禮上丰滑,老公的妹妹穿的比我還像新娘顾犹。我一直安慰自己,他們只是感情好褒墨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布炫刷。 她就那樣靜靜地躺著,像睡著了一般郁妈。 火紅的嫁衣襯著肌膚如雪浑玛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天圃庭,我揣著相機(jī)與錄音锄奢,去河邊找鬼失晴。 笑死剧腻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的涂屁。 我是一名探鬼主播书在,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拆又!你這毒婦竟也來了儒旬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤帖族,失蹤者是張志新(化名)和其女友劉穎栈源,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體竖般,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡甚垦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艰亮。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡闭翩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出迄埃,到底是詐尸還是另有隱情疗韵,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布侄非,位于F島的核電站蕉汪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏逞怨。R本人自食惡果不足惜肤无,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望骇钦。 院中可真熱鬧宛渐,春花似錦、人聲如沸眯搭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鳞仙。三九已至寇蚊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間棍好,已是汗流浹背仗岸。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留借笙,地道東北人扒怖。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像业稼,于是被迫代替她去往敵國和親盗痒。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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