跳到主要内容
版本:6.0.2

配置 JobRepository

DeepSeek V3 中英对照 Configuring a JobRepository

先前所述,JobRepository 用于对 Spring Batch 中各种持久化领域对象(如 JobExecutionStepExecution)执行基本的 CRUD 操作。许多核心框架功能(如 JobOperatorJobStep)都需要它。

配置无资源 JobRepository

JobRepository 接口最简单的实现是 ResourcelessJobRepository。此实现不使用或存储批处理元数据。它适用于不需要重启能力且执行上下文完全不参与的场景(例如通过执行上下文在步骤间共享数据,或通过执行上下文在管理器与工作器之间共享分区元数据的分区步骤等)。该实现仅维护运行单个作业所需的最小状态(即 1 个作业实例 + 1 个作业执行 + N 个步骤执行)。这适用于在独立 JVM 中执行的一次性作业。此作业仓库既支持事务性步骤,也支持非事务性步骤(需与 ResourcelessTransactionManager 配合使用)。

important

此实现并非线程安全,不应在任何并发环境中使用。

默认情况下,当使用 @EnableBatchProcessingDefaultBatchConfiguration 时,系统会为你提供一个 ResourcelessJobRepository

配置 JDBC JobRepository

当使用 @EnableBatchProcessing 时,系统会为你提供一个 ResourcelessJobRepository。本节介绍如何自定义它。Spring Batch 提供了两种由数据库支持的 JobRepository 接口实现:一种是 JDBC 实现(可用于任何符合 JDBC 标准的数据库),另一种是 MongoDB 实现。这两种实现分别由 @EnableJdbcJobRepository@EnableMongoJobRepository 注解提供。

以下示例展示了如何通过 @EnableJdbcJobRepository 注解的属性自定义基于 JDBC 的作业仓库:

@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository(
dataSourceRef = "batchDataSource",
transactionManagerRef = "batchTransactionManager",
tablePrefix = "BATCH_",
maxVarCharLength = 1000,
isolationLevelForCreate = "SERIALIZABLE")
public class MyJobConfiguration {

// job definition

}

此处列出的配置选项都不是必需的。如果未设置,则使用前面显示的默认值。最大 varchar 长度默认为 2500,这是示例模式脚本中长 VARCHAR 列的长度。

配置 MongoDB JobRepository

与基于 JDBC 的 JobRepository 类似,基于 MongoDB 的 JobRepository 也需要一些集合来存储批处理元数据。这些集合定义在 spring-batch-core jar 包的 org/springframework/batch/core/schema-mongodb.jsonl 文件中。与基于 JDBC 的 JobRepository 一样,您需要在运行任何作业之前,在您的 MongoDB 数据库中创建这些集合。

此外,由于在MongoDB文档的字段名中使用.不被推荐的,你需要自定义MongoJobRepositoryFactoryBean所使用的MongoTemplate,将字段名中的.替换为其他字符(例如_)。这可以通过自定义MongoTemplate所使用的MappingMongoConverter来实现。以下示例展示了如何在Java配置中完成此操作:

@Bean
public MongoTemplate mongoTemplate(MongoDatabaseFactory mongoDatabaseFactory) {
MongoTemplate template = new MongoTemplate(mongoDatabaseFactory);
MappingMongoConverter converter = (MappingMongoConverter) template.getConverter();
converter.setMapKeyDotReplacement("_");
return template;
}

JobRepository 的事务配置

如果使用了命名空间或提供的 FactoryBean,事务性建议会自动在存储库周围创建。这是为了确保批处理元数据(包括故障后重启所需的状态)能够被正确持久化。如果存储库方法不是事务性的,框架的行为将无法明确定义。create* 方法属性中的隔离级别被单独指定,以确保在启动作业时,如果两个进程试图同时启动同一个作业,只有一个会成功。该方法的默认隔离级别是 SERIALIZABLE,这是相当严格的。通常 READ_COMMITTED 也能很好地工作。如果两个进程不太可能以这种方式冲突,READ_UNCOMMITTED 也是可以的。然而,由于对 create* 方法的调用非常短暂,只要数据库平台支持,SERIALIZED 不太可能导致问题。不过,你可以覆盖此设置。

以下示例展示了如何在 Java 中覆盖隔离级别:

@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository(isolationLevelForCreate = "ISOLATION_REPEATABLE_READ")
public class MyJobConfiguration {

// 作业定义

}

如果未使用命名空间,则必须通过使用 AOP 来配置存储库的事务行为。

以下示例展示了如何在 Java 中配置存储库的事务行为:

@Bean
public TransactionProxyFactoryBean baseProxy() {
TransactionProxyFactoryBean transactionProxyFactoryBean = new TransactionProxyFactoryBean();
Properties transactionAttributes = new Properties();
transactionAttributes.setProperty("*", "PROPAGATION_REQUIRED");
transactionProxyFactoryBean.setTransactionAttributes(transactionAttributes);
transactionProxyFactoryBean.setTarget(jobRepository());
transactionProxyFactoryBean.setTransactionManager(transactionManager());
return transactionProxyFactoryBean;
}

更改表前缀

JobRepository 的另一个可修改属性是元数据表的表前缀。默认情况下,它们都以 BATCH_ 开头。BATCH_JOB_EXECUTIONBATCH_STEP_EXECUTION 就是两个例子。然而,修改此前缀可能存在一些原因。如果需要在表名前添加模式名称,或者在同一模式中需要多组元数据表,就需要更改表前缀。

以下示例展示了如何在 Java 中更改表前缀:

@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository(tablePrefix = "SYSTEM.TEST_")
public class MyJobConfiguration {

// job definition

}

根据之前的更改,对元数据表的每次查询都会以 SYSTEM.TEST_ 作为前缀。BATCH_JOB_EXECUTION 现在被引用为 SYSTEM.TEST_JOB_EXECUTION

备注

仅表前缀可配置,表和列名不可配置。

仓库中的非标准数据库类型

如果您使用的数据库平台不在支持平台列表中,但SQL变体足够接近,您仍有可能使用其中一种受支持的类型。为此,您可以使用原始的 JdbcJobRepositoryFactoryBean 而非命名空间快捷方式,并通过它设置数据库类型为最接近的匹配项。

以下示例展示了如何在 Java 中使用 JdbcJobRepositoryFactoryBean 将数据库类型设置为最接近的匹配项:

@Bean
public JobRepository jobRepository() throws Exception {
JdbcJobRepositoryFactoryBean factory = new JdbcJobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setDatabaseType("db2");
factory.setTransactionManager(transactionManager);
return factory.getObject();
}

如果未指定数据库类型,JdbcJobRepositoryFactoryBean 会尝试从 DataSource 自动检测数据库类型。不同平台之间的主要差异主要体现在主键递增策略上,因此通常也需要覆盖 incrementerFactory(通过使用 Spring Framework 中的某个标准实现)。

如果上述方法仍然无效,或者您没有使用关系型数据库管理系统(RDBMS),那么唯一的选择可能就是实现 SimpleJobRepository 所依赖的各种 Dao 接口,并按照常规的 Spring 方式手动装配一个实例。