元数据模式
概述
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 模型。
示例 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
版本所需的脚本。
版本
本附录中讨论的许多数据库表都包含一个版本列。此列很重要,因为 Spring Batch 在处理数据库更新时采用乐观锁策略。这意味着每次“触碰”(更新)记录时,版本列中的值都会递增 1。当存储库返回保存值时,如果版本号已更改,则会抛出 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
对象获得的作业名称。因为它必须标识实例,所以它不能为 null。 -
JOB_KEY
:JobParameters
的序列化,它使同一作业的不同实例彼此唯一区分。(具有相同作业名称的JobInstances
必须具有不同的JobParameters
,因此具有不同的JOB_KEY
值)。
BATCH_JOB_EXECUTION_PARAMS
表
BATCH_JOB_EXECUTION_PARAMS
表包含与 JobParameters
对象相关的所有信息。它包含传递给 Job
的零个或多个键值对,并作为作业运行参数的记录。对于有助于生成作业标识的每个参数,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
恰好有一个 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
列的长度加倍就足够了。其他人更喜欢使用 max-varchar-length
配置 JobRepository,其值为 VARCHAR
列长度的一半。一些用户还报告说,他们在模式定义中使用 NVARCHAR
代替 VARCHAR
。最佳结果取决于数据库平台和数据库服务器的本地配置方式。
关于索引元数据表的建议
Spring Batch 为多个常用数据库平台的核心 jar 文件中提供了元数据表的 DDL 示例。索引声明未包含在该 DDL 中,因为根据用户的精确平台、本地约定以及作业操作的业务需求,用户可能希望索引的方式变化太多。下表提供了一些指示,说明 Spring Batch 提供的 DAO 实现将在哪个列中使用 WHERE
子句,以及它们可能使用的频率,以便各个项目可以自己决定是否进行索引。
默认表名 |
WHERE 子句 |
频率 |
|
|
每次启动作业时 |
|
|
每次重新启动作业时 |
|
|
在提交间隔(也称为块)以及步骤开始和结束时 |
|
|
在每次步骤执行之前 |