Spring Batch配置TaskExecutor后提示未识别及数据丢失问题求助
环境信息
- JDK版本:11
- Spring Boot版本:2.6.3
配置代码
@RequiredArgsConstructor @Configuration @Slf4j @EnableBatchProcessing public class SpringBatchConfig { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; @Autowired @Lazy private CRMTService crmtService; @Bean public TaskExecutor myTaskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(15); executor.setQueueCapacity(100); executor.setThreadNamePrefix("Batch-"); executor.initialize(); return executor; } @Bean public Step step() { return stepBuilderFactory.get("step") .<String, String>chunk(10) .reader(itemReader()) .processor(itemProcessor()) .writer(itemWriter()) .taskExecutor(myTaskExecutor()) .build(); } @Bean public Job job() { return jobBuilderFactory.get("job") .start(step()) .build(); } @Bean @StepScope public ItemReader<String> itemReader() { List<String> list = crmtService.getVertrags(); return new IteratorItemReader<>(list != null ? list.iterator() : Collections.emptyIterator()); } @Bean @StepScope public ItemProcessor<String, String> itemProcessor() { return item -> { //Logic -> This calls a method in service class. In that method I am calling an API for each string and saving the response to mongodb. return item; }; } @Bean @StepScope public ItemWriter<String> itemWriter() { return items -> { //If we plan to log do anything in future }; } }
异常现象
- 任务触发时控制台日志提示:
WARN [] 9758 --- [onPool-worker-1] o.s.b.c.c.a.DefaultBatchConfigurer : No datasource was provided...using a Map based JobRepository
WARN [] 9758 --- [onPool-worker-1] o.s.b.c.c.a.DefaultBatchConfigurer : No transaction manager was provided, using a ResourcelessTransactionManager
INFO [] 9758 --- [onPool-worker-1] o.s.b.c.l.support.SimpleJobLauncher : No TaskExecutor has been set, defaulting to synchronous executor.
任务实际运行时,控制台可见线程名称以自定义的「Batch-」前缀开头,说明使用了自定义的myTaskExecutor线程池。
使用TaskExecutor后,MongoDB入库丢失1-2条数据(未使用时可全部入库214条)。
问题与解答
问题1:为何已显式配置TaskExecutor,仍会收到「未设置TaskExecutor,默认使用同步执行器」的提示?
这个日志提示的是**JobLauncher(任务启动器)**没有配置TaskExecutor,和你在Step里配置的TaskExecutor不是同一概念:
- Step级别的TaskExecutor负责并行处理Step内部的chunk数据(比如多线程执行reader/processor/writer);
- JobLauncher的TaskExecutor负责异步启动整个Job(让Job在后台线程运行,不阻塞当前线程)。
你当前的配置里没有给SimpleJobLauncher设置TaskExecutor,所以它默认用同步执行器启动Job,但这完全不影响Step本身使用自己的线程池并行处理数据。
问题2:既然TaskExecutor未被识别,为何运行线程是自定义的Batch前缀线程?
不存在「TaskExecutor未被识别」的情况,日志提示是针对JobLauncher的,而你在Step里配置的TaskExecutor是完全生效的:
- Step启动后,会使用你配置的
myTaskExecutor来并行处理chunk,所以运行时线程名称会带有「Batch-」前缀; - JobLauncher只是同步启动了整个Job流程,后续Step的执行完全由自己的TaskExecutor管理,两者互不冲突。
额外建议:数据丢失问题排查
使用多线程后出现数据丢失,大概率和以下两点有关:
- IteratorItemReader线程不安全:Iterator本身不是线程安全的,多线程环境下多个线程同时读取会导致数据重复或丢失,建议改用
ListItemReader(它是线程安全的,内部用CopyOnWriteArrayList实现):
@Bean @StepScope public ItemReader<String> itemReader() { List<String> list = crmtService.getVertrags(); return new ListItemReader<>(list != null ? list : Collections.emptyList()); }
- 事务管理器不支持多线程事务:当前使用的
ResourcelessTransactionManager是无资源的事务管理器,不支持真正的事务提交,多线程下数据入库可能因为没有事务保障导致部分操作失败。如果使用MongoDB,建议配置MongoDB的事务管理器MongoTransactionManager,并确保MongoDB开启了事务支持(副本集或分片集群环境)。
内容的提问来源于stack exchange,提问作者Shivam Anand

