配置 JobRepository
如前所述,JobRepository 用于在 Spring Batch 中对各种持久化的域对象进行基本的 CRUD 操作,例如 JobExecution
和 StepExecution
。许多主要的框架功能都需要它,例如 JobLauncher
、Job
和 Step
。
- Java
- XML
当使用 @EnableBatchProcessing
时,会为你提供一个 JobRepository
。本节描述了如何对其进行自定义。可以通过 @EnableBatchProcessing
注解的属性指定作业存储库的配置选项,如下例所示:
@Configuration
@EnableBatchProcessing(
dataSourceRef = "batchDataSource",
transactionManagerRef = "batchTransactionManager",
tablePrefix = "BATCH_",
maxVarCharLength = 1000,
isolationLevelForCreate = "SERIALIZABLE")
public class MyJobConfiguration {
// 作业定义
}
这里列出的配置选项都不是必需的。如果没有设置它们,则使用前面显示的默认值。varchar
的最大长度默认为 2500
,这是 示例模式脚本 中长 VARCHAR
列的长度。
批处理命名空间抽象了许多 JobRepository
实现及其协作者的实现细节。然而,仍然有一些配置选项可用,如下例所示:
<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
列的长度。
作业存储库的事务配置
如果使用了命名空间或提供的 FactoryBean
,事务建议会自动围绕存储库创建。这是为了确保批处理元数据(包括失败后重启所需的必要状态)能够正确持久化。如果存储库方法不是事务性的,框架的行为将无法很好地定义。在 create*
方法属性中,隔离级别是单独指定的,以确保在启动作业时,如果有两个进程同时尝试启动同一个作业,只有其中一个能够成功。该方法的默认隔离级别是 SERIALIZABLE
,这是一个非常严格的级别。通常,READ_COMMITTED
也能达到相同的效果。如果两个进程不太可能以这种方式发生冲突,READ_UNCOMMITTED
也可以接受。然而,由于调用 create*
方法的时间很短,只要数据库平台支持,SERIALIZED
很少会导致问题。不过,您可以覆盖此设置。
- Java
- XML
下面的示例展示了如何在 Java 中覆盖隔离级别:
@Configuration
@EnableBatchProcessing(isolationLevelForCreate = "ISOLATION_REPEATABLE_READ")
public class MyJobConfiguration {
// job definition
}
下面的示例展示了如何在 XML 中覆盖隔离级别:
<job-repository id="jobRepository"
isolation-level-for-create="REPEATABLE_READ" />
如果未使用命名空间,则还必须通过使用 AOP 配置存储库的事务行为。
- Java
- XML
下面的示例展示了如何在 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 中配置存储库的事务行为:
<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-tx
和 spring-aop
(或整个 Spring)在类路径上。
更改表前缀
JobRepository
的另一个可修改属性是元数据表的表前缀。默认情况下,所有表都以 BATCH_
为前缀。BATCH_JOB_EXECUTION
和 BATCH_STEP_EXECUTION
就是两个例子。然而,修改这个前缀可能存在一些原因。如果需要在表名前添加模式名称,或者在同一模式内需要多组元数据表,则需要更改表前缀。
- Java
- XML
下面的示例展示了如何在 Java 中更改表前缀:
@Configuration
@EnableBatchProcessing(tablePrefix = "SYSTEM.TEST_")
public class MyJobConfiguration {
// job definition
}
下面的示例展示了如何在 XML 中更改表前缀:
<job-repository id="jobRepository"
table-prefix="SYSTEM.TEST_" />
鉴于前面的更改,对元数据表的每个查询都以前缀 SYSTEM.TEST_
开始。BATCH_JOB_EXECUTION
被称为 SYSTEM.TEST_JOB_EXECUTION
。
仅表前缀是可配置的。表名和列名则不是。
仓库中的非标准数据库类型
如果你使用的数据库平台不在受支持平台的列表中,那么如果 SQL 变体足够接近,你可以使用其中一种受支持的类型。为此,你可以使用原始的 JobRepositoryFactoryBean
而不是命名空间快捷方式,并用它将数据库类型设置为最接近的匹配项。
- Java
- XML
下面的示例展示了如何使用 JobRepositoryFactoryBean
在 Java 中将数据库类型设置为最接近的匹配项:
@Bean
public JobRepository jobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setDatabaseType("db2");
factory.setTransactionManager(transactionManager);
return factory.getObject();
}
下面的示例展示了如何使用 JobRepositoryFactoryBean
在 XML 中将数据库类型设置为最接近的匹配项:
<bean id="jobRepository" class="org...JobRepositoryFactoryBean">
<property name="databaseType" value="db2"/>
<property name="dataSource" ref="dataSource"/>
</bean>
如果未指定数据库类型,JobRepositoryFactoryBean
会尝试从 DataSource
自动检测数据库类型。不同平台之间的主要差异主要体现在主键递增策略上,因此通常还需要覆盖 incrementerFactory
(通过使用 Spring Framework 提供的标准实现之一)。
如果即使这样也不奏效,或者你没有使用关系型数据库管理系统(RDBMS),那么唯一的选择可能是实现 SimpleJobRepository
所依赖的各种 Dao
接口,并以常规的 Spring 方式手动将其连接起来。