|
当前版本仍在开发中,尚不被视为稳定版本。最新稳定版请使用 Spring Batch 文档 6.0.2! |
配置 JobRepository
如前文所述,JobRepository 用于对 Spring Batch 中各类需要持久化的领域对象执行基础 CRUD 操作,
例如 JobExecution 和 StepExecution。它是许多核心框架特性的基础依赖,
例如 JobOperator、Job 和 Step 都需要它。
配置无资源 JobRepository
JobRepository 接口最简单的实现是 ResourcelessJobRepository。
这个实现不会使用或存储任何批处理元数据。它适用于不需要重启能力、也完全不依赖执行上下文的场景
(例如不会通过执行上下文在步骤之间共享数据,或者不会在分区步骤中通过执行上下文在 manager 与 worker 之间共享分区元数据等)。
该实现仅保留运行单个作业所需的最小状态
(即 1 个 job instance + 1 个 job execution + N 个 step execution)。
它适合在独立 JVM 中执行的一次性作业。这个作业仓库既可以与事务性 step 配合使用,
也可以与非事务性 step 配合使用(后者通常结合 ResourcelessTransactionManager)。
| 该实现不是线程安全的,不应用于任何并发环境。 |
默认情况下,使用 @EnableBatchProcessing 或 DefaultBatchConfiguration 时,
Spring Batch 会为你提供一个 ResourcelessJobRepository。
配置 JDBC JobRepository
-
Java
-
XML
使用 @EnableBatchProcessing 时,默认提供的是一个 ResourcelessJobRepository。
本节说明如何对 JobRepository 进行定制。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,
这与示例 schema 脚本中长 VARCHAR 列的长度一致。
Batch 命名空间已经屏蔽了 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,
这与示例 schema 脚本中长 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(Mongo数据库Factory mongo数据库Factory) {
MongoTemplate template = new MongoTemplate(mongo数据库Factory);
MappingMongoConverter converter = (MappingMongoConverter) template.getConverter();
converter.setMapKeyDotReplacement("_");
return template;
}
JobRepository 的事务配置
如果使用了命名空间或框架提供的 FactoryBean,系统会自动在仓库外围创建事务增强。
这样做是为了确保批处理元数据能够被正确持久化,包括失败后重启所需的那些状态信息。
如果仓库方法不具备事务性,框架行为将难以得到可靠定义。
`create*` 方法上的隔离级别之所以被单独指定,是为了确保在启动作业时,如果两个进程同时尝试启动同一个作业,
最终只有一个能够成功。该方法默认的隔离级别是 SERIALIZABLE,这是一个比较激进的设置。
通常 READ_COMMITTED 也同样可行。如果两个进程几乎不可能发生这种冲突,
那么 READ_UNCOMMITTED 也可以接受。不过,由于对 create* 方法的调用通常很短,
只要数据库平台支持,SERIALIZABLE 一般也不太会造成实际问题。当然,你也可以覆盖这个设置。
-
Java
-
XML
下面的示例展示了如何在 Java 中覆盖隔离级别:
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository(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。不过,在某些场景下你可能需要修改此前缀。
例如需要把 schema 名称拼接到表名前,或者同一个 schema 中需要维护多套元数据表时,
就需要变更这个表前缀。
-
Java
-
XML
下面的示例展示了如何在 Java 中修改表前缀:
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository(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 方言与某个已支持平台足够接近,
那么你仍然有机会复用其中一种已支持的类型。为此,你可以不使用命名空间快捷配置,
而是直接使用原始的 JdbcJobRepositoryFactoryBean,并把数据库类型设置为最接近的匹配项。
-
Java
-
XML
下面的示例展示了如何在 Java 中使用 JdbcJobRepositoryFactoryBean,
把数据库类型设置为最接近的匹配项:
@Bean
public JobRepository jobRepository() throws Exception {
JdbcJobRepositoryFactoryBean factory = new JdbcJobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.set数据库Type("db2");
factory.setTransactionManager(transactionManager);
return factory.getObject();
}
下面的示例展示了如何在 XML 中使用 JdbcJobRepositoryFactoryBean,
把数据库类型设置为最接近的匹配项:
<bean id="jobRepository" class="org...JdbcJobRepositoryFactoryBean">
<property name="databaseType" value="db2"/>
<property name="dataSource" ref="dataSource"/>
</bean>
如果没有显式指定数据库类型,JdbcJobRepositoryFactoryBean 会尝试根据 DataSource
自动探测数据库类型。不同平台之间的主要差异通常集中在主键递增策略上,
因此很多时候还需要一并覆盖 incrementerFactory
(通常可使用 Spring Framework 提供的标准实现之一)。
如果即便如此仍然不可行,或者你根本没有使用关系型数据库,那么唯一的选择可能就是自行实现
SimpleJobRepository 所依赖的各个 Dao 接口,
然后按照常规的 Spring 方式手动装配它们。