50万条工资代发,如何保证不全量回滚?

0 阅读5分钟

沉默是金,总会发光

大家好,我是沉默

假设这样一个真实业务场景:

月底,公司要给 50 万名员工发工资

系统从 CSV 文件读取工资数据,然后批量写入银行系统。

流程大致是:

读取工资数据 → 校验数据 → 调用银行接口 → 写入数据库

问题来了:

如果在处理到 第 490000 条记录 时,突然发现:

银行卡号错误

此时如果系统采用 传统事务处理方式

BEGIN
处理 50 万条
COMMIT

那么结果会是:

前面 48 万条成功记录也会全部回滚。

整个批处理直接白干。

这在金融、支付、结算等系统中是 绝对不能接受的

所以企业级系统通常会采用一种特殊处理模式:

Chunk Processing(块级事务)

这正是 Spring Batch 的核心设计。

今天这篇文章,我们就用一个真实案例彻底讲清楚:

Spring Batch 如何处理 50 万数据,并实现部分回滚。

**-**01-

什么是 Spring Batch?

Spring Batch 是 Spring 官方推出的 企业级批处理框架

它专门解决:

  • 批量数据处理
  • 数据迁移
  • ETL
  • 对账系统
  • 报表生成

等问题。

它的核心设计理念:

把大数据拆成小块处理。

Spring Batch 的处理结构非常清晰:

Job
 └── Step
      └── Chunk
           ├── Reader
           ├── Processor
           └── Writer

可以理解为:

组件作用
Job一个完整批处理任务
StepJob中的一个处理步骤
Chunk每次处理的数据块
Reader读取数据
Processor数据处理
Writer数据写入

如果我们设计一个 50万工资代发系统,典型架构如下:

        +------------------+
        |   Web 控制台     |
        | Job监控 / 启停   |
        +--------+---------+
                 |
                 |
        +--------v---------+
        |   Batch Controller |
        |  JobLauncher       |
        +--------+-----------+
                 |
                 |
        +--------v--------+
        |    Spring Batch |
        |                 |
        | Job -> Step     |
        |      -> Chunk   |
        |                 |
        +--------+--------+
                 |
        +--------v--------+
        | 数据存储层       |
        | MySQL / CSV     |
        +-----------------+

整体流程:

CSV文件
   ↓
Reader读取
   ↓
Processor校验
   ↓
Writer写入数据库

图片

- 02-

为什么需要「部分回滚」?

假设:

工资数据 = 500000 条

如果使用 传统事务模式

BEGIN
处理 500000
COMMIT

只要有 1条数据失败

结果就是:

全部回滚

这显然不合理。

所以 Spring Batch 使用:

Chunk事务

假设我们设置:

chunkSize = 1000

那么处理流程是:

50万数据
   │
   ├─ Chunk1  (1-1000)
   ├─ Chunk2  (1001-2000)
   ├─ Chunk3  (2001-3000)
   ├─ ...
   └─ Chunk500

每个 Chunk:

独立事务

流程如下:

读取1000条
   ↓
处理1000条
   ↓
写入1000条
   ↓
提交事务

假设:

Chunk3
2001 - 3000

其中

第2500条数据失败

Spring Batch处理流程:

Chunk3开始
   ↓
读取1000条
   ↓
处理
   ↓
第2500条异常
   ↓
回滚Chunk3
   ↓
重新执行
   ↓
重试3次
   ↓
仍失败
   ↓
跳过该记录
   ↓
提交其余999条

最终结果:

成功:499999
失败:1

这就是 部分回滚机制

图片

- 03-

实际应用场景

关键配置(Skip + Retry)

核心代码如下:

.faultTolerant()
.skipLimit(100)
.skip(IllegalArgumentException.class)
.retryLimit(3)
.retry(Exception.class)

含义:

配置作用
skipLimit最多跳过多少条
skip哪些异常允许跳过
retryLimit失败重试次数
retry哪些异常可以重试

核心处理流程

完整数据流如下:

CSV文件
   │
   ▼
FlatFileItemReader
   │
   ▼
SalaryPaymentProcessor
   │
   ▼
JdbcBatchItemWriter
   │
   ▼
MySQL

具体步骤:

1 数据读取

FlatFileItemReader

读取 CSV。

2 数据验证

校验:

  • 员工ID
  • 金额范围
  • 银行卡号

示例:

if (item.getAmount().compareTo(MAX_AMOUNT) >0) {
    throw new IllegalArgumentException("金额超过限制");
}

3 批量写入

JdbcBatchItemWriter

批量插入数据库。

性能优化

当数据达到:

50万
100万
500万

单线程处理就会变慢。

Spring Batch支持 并行处理

1 多线程处理

Chunk1 -> Thread1
Chunk2 -> Thread2
Chunk3 -> Thread3

配置:

.taskExecutor(taskExecutor())
.throttleLimit(10)

2 Partition 分区处理

适合:

百万级
千万级

结构:

Master Step
   │
   ├─ Partition1
   ├─ Partition2
   ├─ Partition3
   └─ Partition4

每个分区:

独立线程

Spring Batch 元数据表

Spring Batch 会自动创建一些表:

表名作用
BATCH_JOB_INSTANCEJob实例
BATCH_JOB_EXECUTIONJob执行记录
BATCH_STEP_EXECUTIONStep执行记录
BATCH_JOB_EXECUTION_PARAMSJob参数

这些表可以实现:

  • Job恢复
  • Job重启
  • 运行统计

Spring Batch在企业里非常常见:

1 工资代发

50000员工
chunk = 1000

处理50个Chunk。

2 银行对账

100万交易

批量对账。

3 报表生成

每天凌晨

生成:

T+1交易报表

图片

**-****04-**总结

常见问题

Job中途失败怎么办?

Spring Batch支持:

Job Restart

可以:

从失败位置继续

如何重新处理失败数据?

只需要:

查询 status = FAILED

修正后重新执行。

如果你需要处理 几十万甚至百万数据

Spring Batch几乎是最成熟的解决方案。

核心优势:

  • Chunk事务机制

  • 部分回滚

  • 失败重试

  • 跳过策略

  • 任务重启

  • 并行处理

Spring Batch 的本质,就是把「大事务」拆成「小事务」。

这样即使某条数据失败,也不会影响整个任务。

图片

热门文章

一套能保命的高并发实战指南

架构师必备:用 AI 快速生成架构图

**-****05-**粉丝福利

我这里创建一个程序员成长&副业交流群, 


 和一群志同道合的小伙伴,一起聚焦自身发展, 

可以聊:


技术成长与职业规划,分享路线图、面试经验和效率工具, 




探讨多种副业变现路径,从写作课程到私活接单, 




主题活动、打卡挑战和项目组队,让志同道合的伙伴互帮互助、共同进步。 




如果你对这个特别的群,感兴趣的, 
可以加一下, 微信通过后会拉你入群, 
 但是任何人在群里打任何广告,都会被我T掉。