元数据模式
概述
Spring Batch 元数据表与 Java 中表示它们的域对象紧密对应。例如,JobInstance
、JobExecution
、JobParameters
和 StepExecution
分别映射到 BATCH_JOB_INSTANCE
、BATCH_JOB_EXECUTION
、BATCH_JOB_EXECUTION_PARAMS
和 BATCH_STEP_EXECUTION
。ExecutionContext
映射到 BATCH_JOB_EXECUTION_CONTEXT
和 BATCH_STEP_EXECUTION_CONTEXT
。JobRepository
负责将每个 Java 对象保存并存储到其对应的表中。本附录详细描述了元数据表,并介绍了创建这些表时所做的一些设计决策。在查看本附录后面描述的各种表创建语句时,请注意所使用的数据类型尽可能通用。Spring Batch 提供了许多示例模式,由于不同数据库厂商对数据类型的处理方式存在差异,因此这些模式中的数据类型会有所不同。以下图像显示了所有六个表及其相互关系的 ERD 模型:
图 1. Spring Batch 元数据实体关系图
示例 DDL 脚本
Spring Batch Core JAR 文件包含了为多个数据库平台创建关系表的示例脚本(这些脚本会被作业存储库工厂bean 或命名空间等效项自动检测)。这些脚本可以按原样使用,也可以根据需要添加索引和约束进行修改。文件名的形式为 schema-*.sql
,其中 *
是目标数据库平台的简称。这些脚本位于包 org.springframework.batch.core
中。
迁移 DDL 脚本
Spring Batch 在版本升级时提供了迁移 DDL 脚本,你需要执行这些脚本。这些脚本可以在 Core Jar 文件的 org/springframework/batch/core/migration
路径下找到。迁移脚本被组织在与引入它们的版本号相对应的文件夹中:
-
2.2
:包含你需要从2.2
之前的版本迁移到2.2
版本所需的脚本。 -
4.1
:包含你需要从4.1
之前的版本迁移到4.1
版本所需的脚本。
版本
本附录讨论的许多数据库表中包含一个版本列(version column)。这一列非常重要,因为 Spring Batch 在处理数据库更新时采用了乐观锁策略。这意味着每次记录被“修改”(更新)时,版本列中的值会增加 1。当仓库(repository)回去保存该值时,如果版本号已发生变化,它将抛出一个 OptimisticLockingFailureException
,表明并发访问出现了问题。这种检查是必要的,因为即使不同的批处理作业可能在不同的机器上运行,但它们都使用相同的数据库表。
身份
BATCH_JOB_INSTANCE
、BATCH_JOB_EXECUTION
和 BATCH_STEP_EXECUTION
都包含以 _ID
结尾的列。这些字段分别充当其对应表的主键。然而,它们不是数据库生成的键,而是由单独的序列生成的。这是必要的,因为在将其中一个域对象插入数据库后,分配给它的键需要设置到实际的对象上,以便它们可以在 Java 中被唯一标识。较新的数据库驱动程序(JDBC 3.0 及以上版本)通过数据库生成的键支持此功能。然而,为了避免依赖该功能,这里使用了序列。每个模式变体都包含以下形式的某些语句:
CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ;
CREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ;
CREATE SEQUENCE BATCH_JOB_SEQ;
许多数据库供应商不支持序列。在这些情况下,会使用变通方法,例如以下适用于 MySQL 的语句:
CREATE TABLE BATCH_STEP_EXECUTION_SEQ (ID BIGINT NOT NULL) type=InnoDB;
INSERT INTO BATCH_STEP_EXECUTION_SEQ values(0);
CREATE TABLE BATCH_JOB_EXECUTION_SEQ (ID BIGINT NOT NULL) type=InnoDB;
INSERT INTO BATCH_JOB_EXECUTION_SEQ values(0);
CREATE TABLE BATCH_JOB_SEQ (ID BIGINT NOT NULL) type=InnoDB;
INSERT INTO BATCH_JOB_SEQ values(0);
在前面的情况下,每个序列用一张表来代替。然后,Spring 核心类 MySQLMaxValueIncrementer
将此序列中的一个列进行递增,以提供类似的功能。
BATCH_JOB_INSTANCE
表
BATCH_JOB_INSTANCE
表存储了与 JobInstance
相关的所有信息,并且作为整体层次结构的顶层。以下通用的 DDL 语句用于创建该表:
CREATE TABLE BATCH_JOB_INSTANCE (
JOB_INSTANCE_ID BIGINT PRIMARY KEY ,
VERSION BIGINT,
JOB_NAME VARCHAR(100) NOT NULL ,
JOB_KEY VARCHAR(32) NOT NULL
);
以下列表描述了表中的每一列:
-
JOB_INSTANCE_ID
: 用于标识实例的唯一 ID,它也是主键。通过在JobInstance
上调用getId
方法可以获取此列的值。 -
VERSION
: 请参阅 版本。 -
JOB_NAME
: 从Job
对象中获取的任务名称。由于它用于标识实例,因此不能为空。 -
JOB_KEY
:JobParameters
的序列化结果,用于唯一标识同一任务的不同实例。(具有相同任务名称的JobInstances
必须具有不同的JobParameters
,因此其JOB_KEY
值也必须不同)。
BATCH_JOB_EXECUTION_PARAMS
表
BATCH_JOB_EXECUTION_PARAMS
表存储了与 JobParameters
对象相关的所有信息。它包含传递给 Job
的 0 个或多个键值对,并作为记录某项任务运行时所使用参数的依据。对于每个参与生成任务标识的参数,IDENTIFYING
标志会被设置为 true。请注意,该表已经被去规范化。与其为每种类型创建单独的表,不如创建一个带有指示类型的列的表,如下所示:
CREATE TABLE BATCH_JOB_EXECUTION_PARAMS (
JOB_EXECUTION_ID BIGINT NOT NULL ,
PARAMETER_NAME VARCHAR(100) NOT NULL ,
PARAMETER_TYPE VARCHAR(100) NOT NULL ,
PARAMETER_VALUE VARCHAR(2500) ,
IDENTIFYING CHAR(1) NOT NULL ,
constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
);
以下列表描述了每一列:
-
JOB_EXECUTION_ID
:来自BATCH_JOB_EXECUTION
表的外键,表示参数条目所属的作业执行。注意,每条执行记录可能存在多行(即键/值对)。 -
PARAMETER_NAME:参数名称。
-
PARAMETER_TYPE:参数类型的全限定名称。
-
PARAMETER_VALUE:参数值。
-
IDENTIFYING:标志位,表示该参数是否对相关
JobInstance
的身份标识有贡献。
请注意,此表没有主键。这是因为框架不需要它,因此也没有要求。如果需要,可以添加一个带有数据库生成键的主键,而不会对框架本身造成任何问题。
BATCH_JOB_EXECUTION
表
BATCH_JOB_EXECUTION
表存储了与 JobExecution
对象相关的所有信息。每次运行一个 Job
时,都会有一个新的 JobExecution
被调用,并且该表中会新增一行记录。以下列表显示了 BATCH_JOB_EXECUTION
表的定义:
CREATE TABLE BATCH_JOB_EXECUTION (
JOB_EXECUTION_ID BIGINT PRIMARY KEY ,
VERSION BIGINT,
JOB_INSTANCE_ID BIGINT NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL,
START_TIME TIMESTAMP DEFAULT NULL,
END_TIME TIMESTAMP DEFAULT NULL,
STATUS VARCHAR(10),
EXIT_CODE VARCHAR(20),
EXIT_MESSAGE VARCHAR(2500),
LAST_UPDATED TIMESTAMP,
constraint JOB_INSTANCE_EXECUTION_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;
以下列表描述了每一列:
-
JOB_EXECUTION_ID
:主键,唯一标识此次执行。此列的值可以通过调用JobExecution
对象的getId
方法获取。 -
VERSION
:参见 版本。 -
JOB_INSTANCE_ID
:来自BATCH_JOB_INSTANCE
表的外键。它表示此执行所属的实例。每个实例可能会有多个执行。 -
CREATE_TIME
:表示执行创建时间的时间戳。 -
START_TIME
:表示执行开始时间的时间戳。 -
END_TIME
:表示执行完成时间的时间戳,无论成功或失败。如果作业当前未运行且此列为空值,则表示发生了某种错误,框架在失败前无法进行最后一次保存。 -
STATUS
:表示执行状态的字符字符串。这可能是COMPLETED
、STARTED
等。此列的对象表示形式是BatchStatus
枚举。 -
EXIT_CODE
:表示执行退出代码的字符字符串。在命令行作业的情况下,这可能被转换为数字。 -
EXIT_MESSAGE
:表示作业退出方式的更详细描述的字符字符串。在失败的情况下,这可能包括尽可能多的堆栈跟踪信息。 -
LAST_UPDATED
:表示此执行最后一次持久化的时间戳。
BATCH_STEP_EXECUTION
表
BATCH_STEP_EXECUTION
表存储了与 StepExecution
对象相关的所有信息。此表在许多方面与 BATCH_JOB_EXECUTION
表类似,并且对于每个创建的 JobExecution
,每个 Step
至少有一个条目。以下列表显示了 BATCH_STEP_EXECUTION
表的定义:
CREATE TABLE BATCH_STEP_EXECUTION (
STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,
VERSION BIGINT NOT NULL,
STEP_NAME VARCHAR(100) NOT NULL,
JOB_EXECUTION_ID BIGINT NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL,
START_TIME TIMESTAMP DEFAULT NULL ,
END_TIME TIMESTAMP DEFAULT NULL,
STATUS VARCHAR(10),
COMMIT_COUNT BIGINT ,
READ_COUNT BIGINT ,
FILTER_COUNT BIGINT ,
WRITE_COUNT BIGINT ,
READ_SKIP_COUNT BIGINT ,
WRITE_SKIP_COUNT BIGINT ,
PROCESS_SKIP_COUNT BIGINT ,
ROLLBACK_COUNT BIGINT ,
EXIT_CODE VARCHAR(20) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP,
constraint JOB_EXECUTION_STEP_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;
以下列表描述了每一列:
-
STEP_EXECUTION_ID
: 主键,唯一标识此次执行。此列的值应可通过调用StepExecution
对象的getId
方法获取。 -
VERSION
: 详见 版本。 -
STEP_NAME
: 此执行所属步骤的名称。 -
JOB_EXECUTION_ID
: 来自BATCH_JOB_EXECUTION
表的外键。它指明了此StepExecution
所属的JobExecution
。对于给定的JobExecution
和给定的Step
名称,可能只有一个StepExecution
。 -
START_TIME
: 表示执行开始时间的时间戳。 -
END_TIME
: 表示执行结束时间的时间戳,无论成功还是失败。即使作业当前未运行,此列为空值也表示发生了某种错误,框架在失败前未能完成最后一次保存。 -
STATUS
: 表示执行状态的字符字符串。这可能是COMPLETED
、STARTED
等其他状态。此列的对象表示形式是BatchStatus
枚举。 -
COMMIT_COUNT
: 在此次执行期间,步骤提交事务的次数。 -
READ_COUNT
: 在此次执行期间读取的项目数。 -
FILTER_COUNT
: 在此次执行期间过滤掉的项目数。 -
WRITE_COUNT
: 在此次执行期间写入并提交的项目数。 -
READ_SKIP_COUNT
: 在此次执行期间读取时跳过的项目数。 -
WRITE_SKIP_COUNT
: 在此次执行期间写入时跳过的项目数。 -
PROCESS_SKIP_COUNT
: 在此次执行期间处理时跳过的项目数。 -
ROLLBACK_COUNT
: 在此次执行期间回滚的次数。注意,此计数包括每次回滚发生的情况,包括重试回滚和跳过恢复过程中的回滚。 -
EXIT_CODE
: 表示执行退出代码的字符字符串。在命令行作业的情况下,这可能会转换为数字。 -
EXIT_MESSAGE
: 表示作业退出方式的更详细描述的字符字符串。在失败的情况下,这可能包含尽可能多的堆栈跟踪信息。 -
LAST_UPDATED
: 表示此次执行最后持久化时间的时间戳。
BATCH_JOB_EXECUTION_CONTEXT
表
BATCH_JOB_EXECUTION_CONTEXT
表存储了与 Job
的 ExecutionContext
相关的所有信息。每个 JobExecution
都恰好有一个 Job
ExecutionContext
,它包含了特定作业执行所需的所有作业级别的数据。这些数据通常表示在失败后需要检索的状态,以便 JobInstance
可以“从上次中断的地方继续”。以下列表显示了 BATCH_JOB_EXECUTION_CONTEXT
表的定义:
CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT (
JOB_EXECUTION_ID BIGINT PRIMARY KEY,
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
SERIALIZED_CONTEXT CLOB,
constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;
以下列表描述了每一列:
-
JOB_EXECUTION_ID
:外键,表示上下文所属的JobExecution
。某个执行可能关联多个行。 -
SHORT_CONTEXT
:SERIALIZED_CONTEXT
的字符串版本。 -
SERIALIZED_CONTEXT
:整个上下文,已序列化。
BATCH_STEP_EXECUTION_CONTEXT
表
BATCH_STEP_EXECUTION_CONTEXT
表存储了与 Step
的 ExecutionContext
相关的所有信息。每个 StepExecution
对应 exactly one ExecutionContext
,并且它包含了特定步骤执行需要持久化的所有数据。这些数据通常表示在失败后需要恢复的状态,以便 JobInstance
可以“从断点继续”。以下列出了 BATCH_STEP_EXECUTION_CONTEXT
表的定义:
CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT (
STEP_EXECUTION_ID BIGINT PRIMARY KEY,
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
SERIALIZED_CONTEXT CLOB,
constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)
references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID)
) ;
以下列表描述了每一列:
-
STEP_EXECUTION_ID
:外键,表示上下文所属的StepExecution
。给定的执行可能有多个相关联的行。 -
SHORT_CONTEXT
:SERIALIZED_CONTEXT
的字符串版本。 -
SERIALIZED_CONTEXT
:整个上下文,已序列化。
归档
由于每次运行批处理作业时,多个表中都会有记录项,因此通常会为元数据表创建归档策略。这些表本身旨在显示过去发生事件的记录,通常不会影响任何作业的运行,但有几个与重启相关的显著例外情况:
-
该框架使用元数据表来确定特定的
JobInstance
是否已经运行过。如果它已经运行过,并且该作业不可重新启动,则会抛出异常。 -
如果在未成功完成的情况下删除了
JobInstance
的条目,框架会认为该作业是新的,而不是重新启动。 -
如果作业被重新启动,框架将使用已持久化到
ExecutionContext
的任何数据来恢复Job
的状态。因此,对于未成功完成的作业,从该表中删除任何条目将阻止它们在再次运行时从正确的点开始。
国际化与多字节字符
如果你在业务处理中使用多字节字符集(例如中文或西里尔文),这些字符可能需要存储在 Spring Batch 的数据库模式中。许多用户发现,仅仅将模式中的 VARCHAR
列的长度加倍就足够了。另一些用户则倾向于为 JobRepository 配置 max-varchar-length
,其值为 VARCHAR
列长度的一半。还有一些用户报告说,他们在模式定义中用 NVARCHAR
替代了 VARCHAR
。最佳方案取决于数据库平台以及数据库服务器的本地配置方式。
元数据表索引建议
Spring Batch 在核心 jar 文件中为几个常见的数据库平台提供了元数据表的 DDL 示例。该 DDL 中不包含索引声明,因为用户可能根据其具体的平台、本地约定和作业运行的业务需求,有太多不同的索引方式。下表提供了一些关于哪些列将在 Spring Batch 提供的 DAO 实现中用于 WHERE
子句的提示,并说明了它们可能被使用的频率,以便各个项目可以根据这些信息自行决定如何进行索引:
表 1. SQL 语句中的 WHERE 子句(不包括主键)及其使用频率的近似值。
默认表名 | Where 子句 | 频率 |
---|---|---|
BATCH_JOB_INSTANCE | JOB_NAME = ? and JOB_KEY = ? | 每次启动作业时 |
BATCH_JOB_EXECUTION | JOB_INSTANCE_ID = ? | 每次重新启动作业时 |
BATCH_STEP_EXECUTION | VERSION = ? | 在提交间隔时,即块(chunk)期间(以及步骤的开始和结束时) |
BATCH_STEP_EXECUTION | STEP_NAME = ? and JOB_EXECUTION_ID = ? | 在每次步骤执行之前 |