配置 JobRepository

正如前文所述,JobRepository 用于执行 Spring Batch 中各种持久化领域对象的基本 CRUD 操作,例如 JobExecutionStepExecution。 许多核心框架功能都需要它,例如 JobOperatorJobStepspring-doc.cadn.net.cn

配置无资源的 JobRepository

JobRepository 接口的最简单实现是ResourcelessJobRepository。此实现不使用或存储批处理元数据。它适用于不需要可重启性且执行上下文不参与任何操作的用例(例如通过执行上下文在步骤之间共享数据,或在分区步骤中通过执行上下文在管理器和工作者之间共享分区元数据等)。此实现仅持有运行单个作业所需的最小状态(即 1 个作业实例 + 1 个作业执行 + N 个步骤执行)。这适用于在其自有 JVM 中执行的一次性作业。此作业仓库既适用于事务性步骤,也适用于非事务性步骤(与ResourcelessTransactionManager结合使用)。spring-doc.cadn.net.cn

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

默认情况下,当使用 @EnableBatchProcessingDefaultBatchConfiguration 时,系统会为您提供一个 ResourcelessJobRepositoryspring-doc.cadn.net.cn

配置 JDBC JobRepository

当使用 @EnableBatchProcessing 时,系统会为您提供一个 ResourcelessJobRepository。 本节介绍如何对其进行自定义。Spring Batch 提供了两个由数据库支持的 JobRepository 接口实现:一个是 JDBC 实现(可用于任何兼容 JDBC 的数据库),另一个是 MongoDB 实现。这两个实现分别由 @EnableJdbcJobRepository@EnableMongoJobRepository 注解提供。spring-doc.cadn.net.cn

以下示例展示了如何通过 @EnableJdbcJobRepository 注解的属性来自定义基于 JDBC 的作业存储库:spring-doc.cadn.net.cn

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

   // job definition

}

此处列出的配置选项均非必需。 如果未设置,将使用前面显示的默认值。 最大 varchar 长度默认为 2500,即 示例架构脚本中长 VARCHAR 列的长度。spring-doc.cadn.net.cn

批处理命名空间抽象掉了JobRepository实现及其协作者的许多实现细节。然而,如下示例所示,仍有一些配置选项可用:spring-doc.cadn.net.cn

XML 配置
<job-repository id="jobRepository"
    data-source="dataSource"
    transaction-manager="transactionManager"
    isolation-level-for-create="SERIALIZABLE"
    table-prefix="BATCH_"
	max-varchar-length="1000"/>

除了 id 之外,前面列出的所有配置选项都不是必需的。如果未设置它们,将使用前面显示的默认值。 max-varchar-length 的默认值为 2500,这是 示例架构脚本 中长 VARCHAR 列的长度。spring-doc.cadn.net.cn

配置 MongoDB JobRepository

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

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

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 不太可能引发问题。不过,您仍可覆盖此设置。spring-doc.cadn.net.cn

以下示例展示了如何在 Java 中覆盖隔离级别:spring-doc.cadn.net.cn

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

   // job definition

}

以下示例展示了如何在 XML 中覆盖隔离级别:spring-doc.cadn.net.cn

XML 配置
<job-repository id="jobRepository"
                isolation-level-for-create="REPEATABLE_READ" />

如果未使用该命名空间,您还必须使用 AOP 配置仓库的事务行为。spring-doc.cadn.net.cn

以下示例展示了如何在 Java 中配置仓库的事务行为:spring-doc.cadn.net.cn

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;
}

以下示例展示了如何在 XML 中配置仓库的事务行为:spring-doc.cadn.net.cn

XML 配置
<aop:config>
    <aop:advisor
           pointcut="execution(* org.springframework.batch.core..*Repository+.*(..))"/>
    <advice-ref="txAdvice" />
</aop:config>

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" />
    </tx:attributes>
</tx:advice>

您可以几乎原样使用前面的代码片段,无需进行任何更改。同时请记住包含适当的命名空间声明,并确保 spring-txspring-aop(或整个 Spring)位于类路径中。spring-doc.cadn.net.cn

更改表前缀

JobRepository的另一个可修改属性是元数据表的前缀。默认情况下,它们都以BATCH_为前缀。BATCH_JOB_EXECUTIONBATCH_STEP_EXECUTION是两个示例。然而,可能存在需要修改此前缀的情况。如果需要在表名前添加模式名称,或者在同一模式中需要多组元数据表,则需要更改表前缀。spring-doc.cadn.net.cn

以下示例展示了如何在 Java 中更改表前缀:spring-doc.cadn.net.cn

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

   // job definition

}

以下示例展示了如何在 XML 中更改表前缀:spring-doc.cadn.net.cn

XML 配置
<job-repository id="jobRepository"
                table-prefix="SYSTEM.TEST_" />

鉴于上述更改,对元数据表的每个查询都以 SYSTEM.TEST_ 为前缀。BATCH_JOB_EXECUTION 被称为 SYSTEM.TEST_JOB_EXECUTIONspring-doc.cadn.net.cn

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

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

如果您使用的数据库平台不在支持的平台列表中,只要 SQL 变体足够接近,您或许可以使用其中一种受支持的类型。为此,您可以使用原始的 JdbcJobRepositoryFactoryBean 而非命名空间快捷方式,并将其用于将数据库类型设置为最匹配的选项。spring-doc.cadn.net.cn

以下示例展示了如何使用 JdbcJobRepositoryFactoryBean 将数据库类型设置为 Java 中最接近的匹配项:spring-doc.cadn.net.cn

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

以下示例展示了如何使用 JdbcJobRepositoryFactoryBean 在 XML 中将数据库类型设置为最匹配的选项:spring-doc.cadn.net.cn

XML 配置
<bean id="jobRepository" class="org...JdbcJobRepositoryFactoryBean">
    <property name="databaseType" value="db2"/>
    <property name="dataSource" ref="dataSource"/>
</bean>

如果未指定数据库类型,JdbcJobRepositoryFactoryBean 会尝试从 DataSource 自动检测数据库类型。 不同平台之间的主要差异主要体现在主键递增策略上,因此通常还需要重写 incrementerFactory(通过使用 Spring 框架提供的标准实现之一)。spring-doc.cadn.net.cn

如果即使这样也不行,或者您没有使用关系型数据库(RDBMS), 唯一的选项可能是实现 SimpleJobRepository 所依赖的各种 Dao 接口,并以常规的 Spring 方式手动进行装配。spring-doc.cadn.net.cn