Meta-Data Schema

Overview

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 模型:

meta data erd
Figure 1. Spring Batch Meta-Data ERD

Example DDL Scripts

Spring Batch Core JAR 文件包含示例脚本,以便为多个数据库平台创建关系表(这些平台又按照顺序由 jobrepository 工厂 Bean 或名称空间等效项自动检测)。这些脚本可以照原样使用,或者根据需要使用附加索引和约束进行修改。文件名采用表单 schema-.sql,其中 是目标数据库平台的简称。这些脚本位于包 org.springframework.batch.core 中。

Migration DDL Scripts

Spring Batch 提供了在升级版本时需要执行的迁移 DDL 脚本。这些脚本可以在核心 Jar 文件中的 org/springframework/batch/core/migration 下找到。迁移脚本组织成与它们被引用的版本号对应的文件夹:

  • 2.2: 包含您需要从 2.2 之前的版本迁移到的脚本到 2.2 版本的脚本

  • 4.1: 包含您需要从 4.1 之前的版本迁移到的脚本到 4.1 版本的脚本

Version

此附录中讨论的许多数据库表都包含一个版本列。此列非常重要,因为 Spring Batch 在处理数据库更新时采用乐观锁定策略。这意味着,每次记录被“接触”(更新)时,版本列中的值将递增 1。当存储库返回保存值时,如果版本号已更改,它将抛出 OptimisticLockingFailureException,表示并发访问出错。此检查是必要的,因为即使不同批处理作业可能在不同的机器上运行,它们都使用相同的数据库表。

Identity

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 然后递增此序列中的一列以提供类似的功能。

The BATCH_JOB_INSTANCE Table

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: See Version.

  • JOB_NAME: 从 Job 对象中获取的作业的名称。因为它需要识别实例,所以它一定不是空值。

  • JOB_KEY: JobParameters 序列化的内容,该序列化的内容可以唯一地识别相同作业的不同实例(名称相同的 JobInstances 必须有不同的 JobParameters,因此有不同的 JOB_KEY 值)。

The BATCH_JOB_EXECUTION_PARAMS Table

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: The parameter name.

  • PARAMETER_TYPE:参数类型的完全限定名。

  • PARAMETER_VALUE: Parameter value

  • IDENTIFYING:标志,指示参数是否有助于识别相关 JobInstance 的标识。

请注意,此表没有主键。这是因为框架无法使用它,因此不需要它。如果需要,可以添加具有数据库生成键的主键,而不会对框架本身造成任何问题。

The BATCH_JOB_EXECUTION Table

BATCH_JOB_EXECUTION 表保存与 JobExecution 对象相关的所有信息。每次运行 Job 时,总有一个名为 JobExecution 的新 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: See Version.

  • JOB_INSTANCE_ID: 来自 BATCH_JOB_INSTANCE 表的外键。它指示此执行所属的实例。每个实例可能有多个执行。

  • CREATE_TIME: 表示执行创建时间的时间戳。

  • START_TIME: 表示执行开始时间的时间戳。

  • END_TIME: 表示执行完成时间的时间戳,无论成功还是失败。当作业当前未运行时,此列中没有任何值指示发生过某种类型的错误,并且框架无法在执行失败之前执行最后保存。

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

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

  • EXIT_MESSAGE: 表示作业退出的更详细描述的字符字符串。在失败的情况下,这可能包括尽可能多的堆栈跟踪。

  • LAST_UPDATED: 表示此执行最后持久化的时间戳。

The BATCH_STEP_EXECUTION Table

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: See Version.

  • STEP_NAME: 所属执行步骤的名称。

  • JOB_EXECUTION_ID: BATCH_JOB_EXECUTION 表的外键。指示此 StepExecution 所属 STEP_NAME。对于给定 Step 名称,给定 JobExecution 可能只有一个 StepExecution

  • START_TIME: 表示执行开始时间的时间戳。

  • END_TIME: 时间戳,表示执行完成的时间,无论成功还是失败。此列中的空值表示出现某种类型的错误,并且框架在出现故障前无法执行最后保存,即使作业当前未运行。

  • 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: 表示此执行最后持久化的时间戳。

The BATCH_JOB_EXECUTION_CONTEXT Table

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: 整个序列化的上下文。

The BATCH_STEP_EXECUTION_CONTEXT Table

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: 整个序列化的上下文。

Archiving

因为每次运行批处理作业时都会在多个表中创建条目,所以为元数据表创建归档策略很常见。这些表本身旨在显示过去发生的事情的记录,并且通常不会影响任何作业的运行,除了与重启相关的几个值得注意的例外情况:

  • 框架使用元数据表来确定某个特定 JobInstance 是否之前已经运行过。如果已运行过并且作业不可重启,则会引发异常。

  • 如果未成功完成就删除某个 JobInstance 的条目,则框架会将作业视为新的作业,而不是重启。

  • 如果重启作业,则框架会使用已持久存储到 ExecutionContext 的任何数据来恢复 Job’s 状态。因此,为尚未成功完成的作业从该表中删除任何条目都会阻止它们在再次运行时从正确的点开始。

International and Multi-byte Characters

如果你在你的业务处理中使用多字节字符集(如中文或西里尔文),这些字符可能需要保留在 Spring Batch 模式中。许多用户发现,仅仅将模式更改为两倍 VARCHAR`列的长度就足够了。其他人更喜欢将 JobRepository配置为 `max-varchar-length`的一半。`VARCHAR`列长度值。一些用户还报告说他们在模式定义中使用 `NVARCHAR`代替 `VARCHAR。最佳结果取决于数据库平台和数据库服务器在本地配置的方式。

Recommendations for Indexing Metadata Tables

Spring Batch 为核心 jar 文件中的几个常用数据库平台提供元数据表的 DDL 样本。该 DDL 中不包含索引声明,因为存在太多关于用户如何进行索引的变体,具体取决于其精确平台、本地约定以及作业操作的业务需求。下表提供了一些指示,说明 Spring Batch 提供的 DAO 实现将在 WHERE 子句中使用哪些列以及可能使用它们的频率,以便各个项目可以决定自己的索引:

Table 1. Where clauses in SQL statements (excluding primary keys) and their approximate frequency of use.

Default Table Name

Where Clause

Frequency

BATCH_JOB_INSTANCE

write

每次启动作业时

BATCH_JOB_EXECUTION

JOB_INSTANCE_ID = ?

每次重启作业时

BATCH_STEP_EXECUTION

VERSION = ?

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

BATCH_STEP_EXECUTION

STEP_NAME = ? and JOB_EXECUTION_ID = ?

Before each step execution