You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot集成Spring Batch运行时CSV数据重复写入数据库问题

解决Spring Batch重复导入CSV数据的问题

问题根源

你当前使用RunIdIncrementer作为作业增量器,每次启动应用时都会生成新的run.id参数,Spring Batch会将其判定为新的作业实例,从而重复执行整个导入流程,导致CSV数据持续追加到数据库。以下是几种可行的解决方案:


方案1:阻止作业重复自动执行

修改作业配置,移除自动生成新作业实例的增量器,同时配置作业不允许重复执行:

@Bean
public Job importUserJob(JobCompletionNotificationListener listener) {
    return jobBuilderFactory.get("importUserJob")
            .preventRestart() // 标记作业完成后不允许重启
            .listener(listener)
            .flow(step1())
            .end()
            .build();
}

如果需要保留手动触发作业的能力,但避免应用启动时自动重复执行,可以添加作业执行状态检查:

@Bean
public Job importUserJob(JobCompletionNotificationListener listener, JobExplorer jobExplorer) {
    Job job = jobBuilderFactory.get("importUserJob")
            .listener(listener)
            .flow(step1())
            .end()
            .build();

    // 检查作业是否已完成过,避免启动时重复执行
    Set<JobInstance> jobInstances = jobExplorer.getJobInstances("importUserJob", 0, 1);
    if (!jobInstances.isEmpty()) {
        JobInstance jobInstance = jobInstances.iterator().next();
        JobExecution execution = jobExplorer.getJobExecution(jobInstance.getJobInstanceId());
        if (execution != null && execution.getStatus() == BatchStatus.COMPLETED) {
            return job;
        }
    }
    return job;
}

方案2:数据库层面添加唯一约束

在Covid对应的数据库表中,给唯一标识字段(比如id)添加唯一索引,从根源上阻止重复数据插入。同时配置Spring Batch跳过唯一约束冲突的异常:

1. 数据库表添加唯一索引

ALTER TABLE covid ADD UNIQUE KEY uk_covid_id (id);

2. 修改Step配置跳过异常

@Bean
public Step step1(ItemReader<Covid> reader, ItemProcessor<Covid, Covid> processor, ItemWriter<Covid> writer) {
    return stepBuilderFactory.get("step1")
            .<Covid, Covid>chunk(10)
            .reader(reader)
            .processor(processor)
            .writer(writer)
            .faultTolerant()
            .skip(SQLIntegrityConstraintViolationException.class) // 跳过唯一约束冲突异常
            .skipLimit(100) // 根据实际数据量设置允许跳过的次数
            .build();
}

方案3:在ItemProcessor中过滤已存在数据

编写自定义处理器,在数据写入前检查数据库是否已存在该记录,存在则跳过:

1. 实现去重处理器

@Component
public class DuplicateCovidProcessor implements ItemProcessor<Covid, Covid> {

    @Autowired
    private CovidRepository covidRepository; // 注入对应的数据访问层Bean

    @Override
    public Covid process(Covid item) throws Exception {
        // 根据唯一标识检查数据库中是否已存在
        if (covidRepository.existsById(item.getId())) {
            return null; // 返回null表示跳过当前记录
        }
        return item;
    }
}

2. 修改Step配置添加处理器

@Bean
public Step step1(ItemReader<Covid> reader, DuplicateCovidProcessor processor, ItemWriter<Covid> writer) {
    return stepBuilderFactory.get("step1")
            .<Covid, Covid>chunk(10)
            .reader(reader)
            .processor(processor) // 加入去重处理器
            .writer(writer)
            .build();
}

额外配置优化

你的application.properties中spring.batch.jdbc.initialize-schema=always会在每次启动时重新初始化Batch元数据表,可能导致作业执行记录丢失,建议修改为:

# 仅在嵌入式数据库时初始化,生产环境建议手动创建元数据表后设置为never
spring.batch.jdbc.initialize-schema=embedded

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 09:02:37