偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Spring Batch 批處理零基礎(chǔ)速成指南,效率飆升 500%!

開(kāi)發(fā) 前端
如果你還在為批處理任務(wù)頭疼,不妨試試 Spring Batch。相信我,學(xué)會(huì)它之后,你會(huì)發(fā)現(xiàn)批處理原來(lái)可以這么簡(jiǎn)單、這么高效!

兄弟們,有沒(méi)有遇到過(guò)這種情況:每個(gè)月最后一天都要手動(dòng)執(zhí)行幾十條 SQL 清理過(guò)期數(shù)據(jù),結(jié)果因?yàn)橥浖?LIMIT 導(dǎo)致數(shù)據(jù)庫(kù)鎖表,被 DBA 追著打?或者為了生成一份報(bào)表,不得不寫(xiě)個(gè) for 循環(huán)從數(shù)據(jù)庫(kù)查數(shù)據(jù),結(jié)果因?yàn)閮?nèi)存溢出把服務(wù)器干掛了?

這就是傳統(tǒng)批處理的「坑爹日常」—— 手動(dòng)操作易出錯(cuò)、代碼重復(fù)率高、性能還拉胯。但別急,Spring Batch 就是來(lái)拯救你的!這個(gè) Spring 親兒子框架,能讓你用寫(xiě)業(yè)務(wù)代碼的時(shí)間,搞定原本需要加班三天的批量任務(wù),效率直接飆升 500%。

一、傳統(tǒng)批處理的三大「坑王之王」

在正式發(fā)車(chē)前,咱們先聊聊傳統(tǒng)批處理的「三大罪狀」,看看你有沒(méi)有中過(guò)招:

1. 手動(dòng)操作:程序員的「反人類(lèi)設(shè)計(jì)」

想象一下,你要?jiǎng)h除數(shù)據(jù)庫(kù)里 100 萬(wàn)條過(guò)期訂單數(shù)據(jù)。傳統(tǒng)做法是寫(xiě)個(gè)循環(huán),每次刪 5000 條:

DELETE FROM active_orders 
WHERE create_time < '2023-01-01'
LIMIT 5000;

然后手動(dòng)執(zhí)行幾十次,直到?jīng)]數(shù)據(jù)為止。這要是漏執(zhí)行一次,第二天就得面對(duì)產(chǎn)品經(jīng)理的「親切問(wèn)候」。

2. 多線程:程序員的「噩夢(mèng)工廠」

為了提升性能,你可能會(huì)用多線程處理數(shù)據(jù)。但寫(xiě)出來(lái)的代碼往往像這樣:

ExecutorService executor = Executors.newFixedThreadPool(8);
while (hasNextPage()) {
    List<Data> page = fetchNextPage();
    executor.submit(() -> processPage(page));
}
// 忘記調(diào)用 shutdown(),線程池直接爆炸!

結(jié)果就是內(nèi)存泄漏、數(shù)據(jù)庫(kù)連接泄露,服務(wù)器分分鐘變成「烤雞」。

3. 配置管理:程序員的「智商檢測(cè)器」

參數(shù)寫(xiě)死在代碼里,改個(gè)批量大小就得重新打包部署;不同環(huán)境配置混雜,測(cè)試環(huán)境跑好好的,一到生產(chǎn)就報(bào)錯(cuò)。這時(shí)候你只能對(duì)著屏幕大喊:「這鍋我不背!」

二、Spring Batch:批處理界的「瑞士軍刀」

Spring Batch 就像程序員的「智能管家」,幫你搞定所有臟活累活。它的核心優(yōu)勢(shì)可以用三個(gè)詞概括:自動(dòng)化、健壯性、可擴(kuò)展性。

1. 自動(dòng)化流水線:數(shù)據(jù)處理「一鍵三連」

Spring Batch 把批處理抽象成「讀取 → 處理 → 寫(xiě)入」的流水線。比如處理 CSV 文件,你只需要配置好 ItemReader(讀文件)、ItemProcessor(數(shù)據(jù)清洗)、ItemWriter(寫(xiě)入數(shù)據(jù)庫(kù)),剩下的交給框架自動(dòng)完成。

2. 健壯性拉滿:媽媽再也不用擔(dān)心我的代碼

  • 事務(wù)管理:每個(gè)批次(Chunk)作為一個(gè)事務(wù),失敗自動(dòng)回滾,成功才提交。
  • 錯(cuò)誤處理:支持重試(Retry)和跳過(guò)(Skip)機(jī)制。比如某條數(shù)據(jù)格式錯(cuò)誤,跳過(guò)它繼續(xù)處理下一條,而不是整個(gè)任務(wù)崩潰。
  • 斷點(diǎn)續(xù)傳:任務(wù)執(zhí)行到一半失敗?重啟后自動(dòng)從斷點(diǎn)繼續(xù),不用從頭再來(lái)。

3. 性能飆升:從「蝸?!沟健富鸺?/h3>

Spring Batch 內(nèi)置了多種優(yōu)化策略:

  • 批量讀?。菏褂糜螛?biāo)(Cursor)一次性讀取大量數(shù)據(jù),減少數(shù)據(jù)庫(kù)交互次數(shù)。
  • 異步處理:將數(shù)據(jù)處理和寫(xiě)入放到線程池異步執(zhí)行,CPU 利用率直接翻倍。
  • 分區(qū)處理:把大數(shù)據(jù)集拆分成多個(gè)小任務(wù)并行處理,百萬(wàn)級(jí)數(shù)據(jù)分分鐘搞定。

三、Spring Batch 核心組件:四大金剛「組隊(duì)打怪」

Spring Batch 的核心組件可以比作一個(gè)「工廠」:

  • Job(廠長(zhǎng)):負(fù)責(zé)統(tǒng)籌全局,安排任務(wù)流程。
  • Step(車(chē)間主任):具體執(zhí)行任務(wù)的單元,每個(gè) Step 包含完整的「讀取 → 處理 → 寫(xiě)入」流程。
  • ItemReader(搬運(yùn)工):從數(shù)據(jù)源讀取數(shù)據(jù),支持文件、數(shù)據(jù)庫(kù)、消息隊(duì)列等多種來(lái)源。
  • ItemProcessor(質(zhì)檢員):對(duì)數(shù)據(jù)進(jìn)行清洗、轉(zhuǎn)換等處理。
  • ItemWriter(打包工):將處理后的數(shù)據(jù)寫(xiě)入目標(biāo)存儲(chǔ)。

1. Job:任務(wù)指揮官

Job 是批處理的頂級(jí)抽象,一個(gè) Job 可以包含多個(gè) Step。比如銀行的日終對(duì)賬 Job,可能包含下載文件、數(shù)據(jù)校驗(yàn)、生成報(bào)表三個(gè) Step:

@Bean
public Job dailyReconciliationJob(JobBuilderFactory jobBuilderFactory, Step downloadStep, Step validateStep) {
    return jobBuilderFactory.get("dailyReconciliation")
        .start(downloadStep)
        .next(validateStep)
        .build();
}

2. Step:流水線上的「螺絲釘」

Step 是 Job 的執(zhí)行單元,分為兩種類(lèi)型:

  • Chunk-Oriented Step:基于塊處理,適合數(shù)據(jù)量大的場(chǎng)景。
  • Tasklet Step:執(zhí)行單個(gè)任務(wù),適合簡(jiǎn)單的腳本式操作。

Chunk-Oriented Step 的核心是 chunk 方法,指定每次處理的數(shù)據(jù)量:

@Bean
public Step csvImportStep(StepBuilderFactory stepBuilderFactory, ItemReader<User> reader, ItemProcessor<User, User> processor, ItemWriter<User> writer) {
    return stepBuilderFactory.get("csvImport")
        .<User, User>chunk(100) // 每 100 條數(shù)據(jù)提交一次
        .reader(reader)
        .processor(processor)
        .writer(writer)
        .build();
}

3. ItemReader:數(shù)據(jù)搬運(yùn)工

ItemReader 負(fù)責(zé)從數(shù)據(jù)源讀取數(shù)據(jù)。比如讀取 CSV 文件:

@Bean
public ItemReader<User> userReader() {
    FlatFileItemReader<User> reader = new FlatFileItemReader<>();
    reader.setResource(new ClassPathResource("users.csv"));
    reader.setLineMapper(new DefaultLineMapper<>() {{
        setLineTokenizer(new DelimitedLineTokenizer() {{
            setNames("name", "age", "email");
        }});
        setFieldSetMapper(new BeanWrapperFieldSetMapper<>() {{
            setTargetType(User.class);
        }});
    }});
    return reader;
}

4. ItemProcessor:數(shù)據(jù)變形金剛

ItemProcessor 對(duì)數(shù)據(jù)進(jìn)行處理,比如手機(jī)號(hào)脫敏:

public class DataMaskProcessor implements ItemProcessor<User, User> {
    @Override
    public User process(User user) {
        // 手機(jī)號(hào)脫敏:138****1234
        String phone = user.getPhone();
        user.setPhone(phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
        // 郵箱轉(zhuǎn)小寫(xiě)
        user.setEmail(user.getEmail().toLowerCase());
        return user;
    }
}

5. ItemWriter:數(shù)據(jù)收納師

ItemWriter 將數(shù)據(jù)寫(xiě)入目標(biāo)存儲(chǔ)。比如批量寫(xiě)入數(shù)據(jù)庫(kù):

@Bean
public ItemWriter<User> userWriter(JdbcTemplate jdbcTemplate) {
    return items -> {
        for (User user : items) {
            jdbcTemplate.update(
                "INSERT INTO users (name, age, email) VALUES (?, ?, ?)",
                user.getName(),
                user.getAge(),
                user.getEmail()
            );
        }
    };
}


四、實(shí)戰(zhàn)案例:從「Hello World」到「企業(yè)級(jí)應(yīng)用」

案例 1:批量刪除過(guò)期訂單

傳統(tǒng)方法需要手動(dòng)循環(huán)執(zhí)行 SQL,而 Spring Batch 可以這樣做:

  1. 配置 Job 和 Step:
@Bean
public Job deleteExpiredOrdersJob(JobBuilderFactory jobBuilderFactory, Step deleteStep) {
    return jobBuilderFactory.get("deleteExpiredOrders")
        .start(deleteStep)
        .build();
}
@Bean
public Step deleteStep(StepBuilderFactory stepBuilderFactory, ItemReader<Order> reader, ItemWriter<Order> writer) {
    return stepBuilderFactory.get("deleteStep")
        .<Order, Order>chunk(5000)
        .reader(reader)
        .writer(writer)
        .build();
}
  • 實(shí)現(xiàn) ItemReader 和 ItemWriter:
@Bean
public ItemReader<Order> orderReader(JdbcTemplate jdbcTemplate) {
    returnnew JdbcCursorItemReaderBuilder<Order>()
        .sql("SELECT id FROM orders WHERE create_time < ?")
        .parameters("2023-01-01")
        .rowMapper((rs, rowNum) -> new Order(rs.getLong("id")))
        .build();
}

@Bean
public ItemWriter<Order> orderWriter(JdbcTemplate jdbcTemplate) {
    return items -> {
        List<Long> ids = items.stream().map(Order::getId).collect(Collectors.toList());
        jdbcTemplate.update(
            "DELETE FROM orders WHERE id IN (?)",
            ids
        );
    };
}
  • 運(yùn)行結(jié)果:原本需要手動(dòng)執(zhí)行幾十次的任務(wù),現(xiàn)在一鍵運(yùn)行,效率提升 10 倍!

案例 2:日志分析系統(tǒng)

處理 GB 級(jí)別的 Nginx 日志,傳統(tǒng)方法容易內(nèi)存溢出,而 Spring Batch 可以這樣優(yōu)化:

  • 流式讀取日志文件:
@Bean
public ItemReader<String> logReader() {
    return new FlatFileItemReaderBuilder<String>()
        .resource(new FileSystemResource("/var/log/nginx/access.log"))
        .lineMapper(new PassThroughLineMapper())
        .build();
}
  • 異步處理數(shù)據(jù):
@Bean
public Step logProcessingStep(StepBuilderFactory stepBuilderFactory, ItemReader<String> reader, ItemProcessor<String, LogEntry> processor, ItemWriter<LogEntry> writer) {
    return stepBuilderFactory.get("logProcessing")
        .<String, LogEntry>chunk(1000)
        .reader(reader)
        .processor(processor)
        .writer(writer)
        .taskExecutor(new SimpleAsyncTaskExecutor())
        .throttleLimit(10) // 最大并發(fā)線程數(shù)
        .build();
}
  • 結(jié)果:處理 10GB 日志文件僅需 15 分鐘,而傳統(tǒng)方法需要 2 小時(shí)!

五、高級(jí)技巧:讓 Spring Batch 「飛」起來(lái)

1. 異步處理:釋放 CPU 潛能

將數(shù)據(jù)處理和寫(xiě)入放到線程池異步執(zhí)行:

private <I, O> AsyncItemProcessor<I, O> wrapAsyncProcessor(ItemProcessor<I, O> processor, TaskExecutor taskExecutor) {
    AsyncItemProcessor<I, O> asyncProcessor = new AsyncItemProcessor<>();
    asyncProcessor.setDelegate(processor);
    asyncProcessor.setTaskExecutor(taskExecutor);
    return asyncProcessor;
}

private <O> AsyncItemWriter<O> wrapAsyncWriter(ItemWriter<O> writer) {
    AsyncItemWriter<O> asyncWriter = new AsyncItemWriter<>();
    asyncWriter.setDelegate(writer);
    return asyncWriter;
}

@Bean
public Step asyncStep(StepBuilderFactory stepBuilderFactory, ItemReader<PayOrderPo> reader, ItemProcessor<PayOrderPo, PayOrderPo> processor, ItemWriter<PayOrderPo> writer) {
    AsyncItemProcessor<PayOrderPo, PayOrderPo> asyncProcessor = wrapAsyncProcessor(processor, new ThreadPoolTaskExecutor());
    AsyncItemWriter<PayOrderPo> asyncWriter = wrapAsyncWriter(writer);
    return stepBuilderFactory.get("asyncStep")
        .<PayOrderPo, Future<PayOrderPo>>chunk(500)
        .reader(reader)
        .processor(asyncProcessor)
        .writer(asyncWriter)
        .build();
}

2. 分區(qū)處理:大數(shù)據(jù)量「分而治之」

將數(shù)據(jù)按時(shí)間范圍分區(qū),并行處理:

@Bean
public Job partitionJob(JobBuilderFactory jobBuilderFactory, Step partitionStep) {
    return jobBuilderFactory.get("partitionJob")
        .start(partitionStep)
        .build();
}

@Bean
public Step partitionStep(StepBuilderFactory stepBuilderFactory, Step slaveStep) {
    return stepBuilderFactory.get("partitionStep")
        .partitioner("slaveStep", new RangePartitioner<>("id", 0, 1000000, 10))
        .step(slaveStep)
        .gridSize(10) // 并發(fā)分區(qū)數(shù)
        .build();
}

@Bean
public Step slaveStep(StepBuilderFactory stepBuilderFactory, ItemReader<Order> reader, ItemWriter<Order> writer) {
    return stepBuilderFactory.get("slaveStep")
        .<Order, Order>chunk(1000)
        .reader(reader)
        .writer(writer)
        .build();
}

3. 監(jiān)控與調(diào)優(yōu):讓問(wèn)題「無(wú)所遁形」

  • 使用 Spring Boot Actuator:
management:
  endpoints:
    web:
      exposure:
        include: "batch-jobs"

訪問(wèn) /actuator/batch-jobs 可以查看作業(yè)狀態(tài)、執(zhí)行歷史等信息。

  • 性能調(diào)優(yōu)參數(shù):
spring.batch.job:
  parameters:
    chunk-size: 1000 # 每批次處理 1000 條數(shù)據(jù)
    thread-pool-size: 8 # 線程池大小
    max-retries: 3 # 最大重試次數(shù)


六、效率飆升 500% 的秘密:Spring Batch vs 傳統(tǒng)方法

對(duì)比項(xiàng)

傳統(tǒng)方法

Spring Batch

開(kāi)發(fā)效率

從頭編寫(xiě)重復(fù)代碼,開(kāi)發(fā)周期長(zhǎng)

內(nèi)置組件開(kāi)箱即用,開(kāi)發(fā)效率提升 80%

性能

單線程處理,性能低下

異步處理 + 分區(qū)技術(shù),吞吐量提升 5 倍

容錯(cuò)性

手動(dòng)處理異常,容易遺漏

內(nèi)置重試、跳過(guò)機(jī)制,錯(cuò)誤處理效率提升 90%

監(jiān)控與維護(hù)

無(wú)統(tǒng)一監(jiān)控,問(wèn)題排查困難

集成監(jiān)控工具,實(shí)時(shí)查看作業(yè)狀態(tài)

擴(kuò)展性

代碼耦合度高,難以擴(kuò)展

模塊化設(shè)計(jì),輕松應(yīng)對(duì)需求變化


七、最佳實(shí)踐:寫(xiě)出「優(yōu)雅」的批處理代碼

1. 合理設(shè)置批次大?。–hunk Size)

  • 小數(shù)據(jù)量:500-1000 條 / 批次。
  • 大數(shù)據(jù)量:1000-5000 條 / 批次。
  • IO 密集型任務(wù):適當(dāng)增大批次大小,減少 IO 次數(shù)。
  • CPU 密集型任務(wù):適當(dāng)減小批次大小,避免內(nèi)存溢出。

2. 避免狀態(tài)共享

ItemReader、ItemProcessor、ItemWriter 應(yīng)設(shè)計(jì)為無(wú)狀態(tài),確保線程安全。

3. 日志記錄

在關(guān)鍵節(jié)點(diǎn)添加日志,記錄處理進(jìn)度和異常信息:

public class JobCompletionNotificationListener implements JobExecutionListener {
    privatefinal Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class);

    @Override
    public void beforeJob(JobExecution jobExecution) {
        log.info("Job {} started at {}", jobExecution.getJobInstance().getJobName(), new Date());
    }

    @Override
    public void afterJob(JobExecution jobExecution) {
        if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
            log.info("Job {} completed at {} with {} items processed",
                jobExecution.getJobInstance().getJobName(),
                new Date(),
                jobExecution.getExecutionContext().getLong("totalItemsProcessed")
            );
        }
    }
}

4. 配置管理

使用 @Profile 注解區(qū)分不同環(huán)境配置:

@Configuration
@Profile("prod")
public class ProductionConfig {
    // 生產(chǎn)環(huán)境配置
}

@Configuration
@Profile("dev")
public class DevelopmentConfig {
    // 開(kāi)發(fā)環(huán)境配置
}


八、常見(jiàn)問(wèn)題與解決方案

1. 內(nèi)存溢出(OOM)

  • 原因:一次性讀取大量數(shù)據(jù)到內(nèi)存。
  • 解決方案:

使用游標(biāo)(Cursor)流式讀取數(shù)據(jù)。

減小批次大小(Chunk Size)。

啟用垃圾回收(GC)監(jiān)控,優(yōu)化堆內(nèi)存配置。

2. 數(shù)據(jù)庫(kù)連接泄露

  • 原因:未正確關(guān)閉數(shù)據(jù)庫(kù)連接。
  • 解決方案:

使用 Spring 提供的 JdbcCursorItemReader,自動(dòng)管理連接。

在 ItemWriter 中使用批量操作,減少連接次數(shù)。

3. 任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng)

  • 原因:數(shù)據(jù)量過(guò)大或處理邏輯復(fù)雜。
  • 解決方案:

采用分區(qū)處理,并行執(zhí)行多個(gè)任務(wù)。

優(yōu)化 SQL 查詢,添加索引。

將耗時(shí)操作異步化,使用消息隊(duì)列解耦。

九、總結(jié):Spring Batch 是「神器」還是「玩具」?

經(jīng)過(guò)實(shí)戰(zhàn)驗(yàn)證,Spring Batch 絕對(duì)是企業(yè)級(jí)批處理的「神器」。它不僅能大幅提升開(kāi)發(fā)效率和系統(tǒng)性能,還能降低維護(hù)成本和故障風(fēng)險(xiǎn)。無(wú)論是數(shù)據(jù)遷移、報(bào)表生成,還是日志分析、金融對(duì)賬,Spring Batch 都能輕松應(yīng)對(duì)。

如果你還在為批處理任務(wù)頭疼,不妨試試 Spring Batch。相信我,學(xué)會(huì)它之后,你會(huì)發(fā)現(xiàn)批處理原來(lái)可以這么簡(jiǎn)單、這么高效!

責(zé)任編輯:武曉燕 來(lái)源: 石杉的架構(gòu)筆記
相關(guān)推薦

2025-07-09 04:00:00

2025-10-14 09:12:49

2020-12-11 11:26:47

Spring批處理重試

2025-07-29 02:00:00

2022-08-02 20:47:38

Spring框架應(yīng)用程序

2025-08-27 03:22:00

AI智能體系統(tǒng)

2023-08-22 08:01:42

SpringBatch事務(wù)管理

2025-07-23 07:28:24

2012-02-20 09:49:42

ibmdw

2017-05-11 11:00:11

大數(shù)據(jù)Hadoop數(shù)據(jù)處理

2017-05-05 09:53:34

Hadoop大數(shù)據(jù)處理

2020-11-03 15:10:55

Spring Batc框架Java

2017-01-12 14:50:15

大數(shù)據(jù)Spring Batc框架

2017-05-11 17:36:50

2016-11-25 13:05:18

2022-03-15 09:31:17

ESLint工作原理前端

2017-09-21 15:31:49

2012-02-22 10:33:36

Wi-Fi

2025-08-11 07:41:59

2025-06-27 06:30:08

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)