元数据模式

概述

Spring Batch 元数据表与代表它们的 Java 域对象密切匹配。例如,JobInstanceJobExecutionJobParametersStepExecution 分别映射到 BATCH_JOB_INSTANCEBATCH_JOB_EXECUTIONBATCH_JOB_EXECUTION_PARAMSBATCH_STEP_EXECUTIONExecutionContext 映射到 BATCH_JOB_EXECUTION_CONTEXTBATCH_STEP_EXECUTION_CONTEXTJobRepository 负责将每个 Java 对象保存到其正确的表中。本附录详细介绍了元数据表,以及在创建它们时做出的许多设计决策。在查看本附录后面描述的各种表创建语句时,请注意,使用的數據類型尽可能通用。Spring Batch 提供了许多模式作为示例。它们都具有不同的数据类型,因为各个数据库供应商对数据类型的处理方式不同。下图显示了所有六个表及其相互关系的 ERD 模型。

Spring Batch Meta-Data ERD
图 1. 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_INSTANCEBATCH_JOB_EXECUTIONBATCH_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 的 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: 表示执行开始时间的 Timestamp。

  • END_TIME: 表示执行结束时间的 Timestamp,无论成功或失败。如果作业当前未运行,此列为空值,则表示发生某种错误,框架无法在失败之前执行最后保存操作。

  • STATUS: 表示执行状态的字符字符串。这可能是 COMPLETEDSTARTED 等。此列的对象表示是 BatchStatus 枚举。

  • EXIT_CODE: 表示执行退出代码的字符字符串。对于命令行作业,这可以转换为数字。

  • EXIT_MESSAGE: 表示作业退出更详细描述的字符字符串。如果失败,这可能包含尽可能多的堆栈跟踪信息。

  • LAST_UPDATED: 表示上次持久化此执行的 Timestamp。

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: 表示执行开始时间的 Timestamp。

  • END_TIME: 表示执行结束时间的 Timestamp,无论成功或失败。此列为空值,即使作业当前未运行,也表示发生某种错误,框架无法在失败之前执行最后保存操作。

  • STATUS: 表示执行状态的字符字符串。这可能是 COMPLETEDSTARTED 等。此列的对象表示是 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: 表示上次持久化此执行的 Timestamp。

BATCH_JOB_EXECUTION_CONTEXT

BATCH_JOB_EXECUTION_CONTEXT 表包含与JobExecutionContext 相关的所有信息。每个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 表包含与StepExecutionContext 相关的所有信息。每个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子句中使用以及它们可能被使用的频率的指示,以便各个项目可以自行决定是否进行索引。

表 1. SQL 语句中的 WHERE 子句(不包括主键)及其使用频率的近似值。

默认表名

WHERE 子句

频率

BATCH_JOB_INSTANCE

JOB_NAME = ? and JOB_KEY = ?

每次启动作业时

BATCH_JOB_EXECUTION

JOB_INSTANCE_ID = ?

每次重启作业时

批处理步骤执行

版本 = ?

在提交间隔,也称为块(以及在步骤开始和结束时)

批处理步骤执行

步骤名称 = ? 且作业执行 ID = ?

在每个步骤执行之前