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

Spring Batch报错JobRepository must be set的解决及多数据源配置问询

Spring Batch无Spring Boot配置问题:JobRepository未设置错误

我是Spring Batch新手,正在编写无Spring Boot的POC代码,实现从MySQL导出数据到CSV,但运行时出现以下错误:

Failed to instantiate [org.springframework.batch.core.Job]: Factory method 'job' threw exception with message: java.lang.IllegalStateException: JobRepository must be set

我需要解决这个配置遗漏的问题,同时要为JobRepository配置与业务数据源不同的数据源。以下是我的代码:

主类代码

import com.techtalk.debu.batch.entity.Employee;
import org.springframework.batch.core.*;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder;
import org.springframework.batch.item.file.FlatFileItemWriter;
import org.springframework.batch.item.file.builder.FlatFileItemWriterBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.FileSystemResource;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jdbc.support.JdbcTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

@EnableBatchProcessing(dataSourceRef = "batchDataSource", transactionManagerRef = "batchTransactionManager")
public class LoadController {

    @Bean
    public DataSource batchDataSource() {
        return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
                .addScript("/org/springframework/batch/core/schema-h2.sql")
                .generateUniqueName(false).build();
    }

    @Bean
    public DataSource dataSource() {
        DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
        dataSourceBuilder.url("jdbc:mysql://localhost:3306/Test");
        dataSourceBuilder.username("sa");
        dataSourceBuilder.password("1234567890");
        return dataSourceBuilder.build();
    }

    @Bean
    public JdbcTransactionManager batchTransactionManager(DataSource batchDataSource) {
        return new JdbcTransactionManager(batchDataSource);
    }

    public static void main(String e []) throws Exception {

        ApplicationContext context = new AnnotationConfigApplicationContext(LoadController.class);

        JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis()).toJobParameters();


        JobLauncher jobLauncher = context.getBean(JobLauncher.class);

        JobExecution jobExecution = jobLauncher.run(context.getBean(Job.class), jobParameters);
        System.out.println("Job Exit Status : " + jobExecution.getStatus());
    }

    @Bean
    public Step step(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        return new StepBuilder("step", jobRepository)
                .<Employee, Employee>chunk(5, transactionManager)
                .reader(itemReader())
                .writer(itemWriter())           
                .build();
    }

    @Bean
    public JdbcTransactionManager transactionManager(DataSource dataSource) {
        return new JdbcTransactionManager(dataSource);
    }

    @Bean
    public Job job(JobRepository jobRepository, JdbcTransactionManager transactionManager) {
        return new JobBuilder("job")
                .start(step(jobRepository, transactionManager))
                .build();
    }


    @Bean
    public JdbcCursorItemReader<Employee> itemReader() {
        String sql = "select * from person";
        return new JdbcCursorItemReaderBuilder<Employee>()
                .name("personItemReader")
                .dataSource(dataSource())
                .sql(sql)
                .beanRowMapper(Employee.class)
                .build();
    }


    @Bean
    public FlatFileItemWriter<Employee> itemWriter() {
        return new FlatFileItemWriterBuilder<Employee>()
                .resource(new FileSystemResource("persons.csv"))
                .name("personItemWriter")
                .delimited()
                .names("id", "name")
                .build();
    }


}

Maven Pom文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.2</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.techtalk.debu</groupId>
    <artifactId>Spring-Batch-CSV-to-DB-Project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-batch-CSV-To_DB-Write-Example-For-Beginners</name>
    <description>Demo project for Beginners to understand Spring Boot</description>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>17</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>

            <scope>provided</scope>
        </dependency>


        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>3.0.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-core</artifactId>
            <version>5.0.0</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-infrastructure</artifactId>
            <version>5.0.0</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Employee实体类

import jakarta.persistence.*;
import lombok.Data;

import java.util.Date;

@Entity
@Table(name = "user_analytics_table")
@Data
public class Employee {

    @Id
    private String id;
    private String name;
    private String email;
    private String phone_number;


}

问题分析与解决方案

核心问题

创建Job时使用JobBuilder但未传入JobRepository实例,导致框架无法找到必要的作业元数据存储组件。虽然@EnableBatchProcessing已指定batch专用的数据源和事务管理器,但JobBuilder需要显式关联JobRepository才能正常初始化。

修复步骤

  1. 修正Job Bean的创建逻辑
    在job方法中,将JobRepository传入JobBuilder的构造方法(与创建Step的方式一致):

    @Bean
    public Job job(JobRepository jobRepository, JdbcTransactionManager transactionManager) {
        return new JobBuilder("job", jobRepository) // 新增JobRepository参数
                .start(step(jobRepository, transactionManager))
                .build();
    }
    
  2. 规范ItemReader的数据源注入
    当前itemReader()直接调用dataSource()创建新实例,会绕过Spring容器的依赖管理,改为通过方法参数注入业务数据源:

    @Bean
    public JdbcCursorItemReader<Employee> itemReader(DataSource dataSource) {
        String sql = "select * from person";
        return new JdbcCursorItemReaderBuilder<Employee>()
                .name("personItemReader")
                .dataSource(dataSource)
                .sql(sql)
                .beanRowMapper(Employee.class)
                .build();
    }
    
  3. 移除Spring Boot相关依赖(可选)
    若要实现纯无Spring Boot的POC,可替换Pom中的parent和依赖:

    <!-- 替换原Spring Boot parent -->
    <parent>
        <groupId>org.springframework.batch</groupId>
        <artifactId>spring-batch-parent</artifactId>
        <version>5.0.0</version>
        <relativePath />
    </parent>
    <!-- 添加必要的Spring基础依赖,移除Spring Boot相关 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
    </dependency>
    <!-- 移除spring-boot-starter-data-jpa和spring-boot-maven-plugin -->
    

验证效果

修改后,Spring容器会自动将batch专用的JobRepository注入到Job和Step组件中,同时业务数据源与batch数据源相互隔离,满足需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 14:05:31