元数据模式

概述

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-doc.cadn.net.cn

Spring Batch Meta-Data ERD
图 1. Spring Batch 元数据实体关系图(ERD)

示例 DDL 脚本

Spring Batch Core JAR 文件包含用于为多种数据库平台创建关系表的示例脚本(这些平台会由作业存储库工厂 Bean 或等效的命名空间自动检测)。这些脚本可以直接使用,也可以根据需求添加额外的索引和约束进行修改。文件名格式为schema-*.sql,其中*是目标数据库平台的简称。这些脚本位于org.springframework.batch.core包中。spring-doc.cadn.net.cn

迁移 DDL 脚本

Spring Batch 提供了在升级版本时需要执行的迁移 DDL 脚本。 这些脚本可以在 org/springframework/batch/core/migration 下的 Core Jar 文件中找到。 迁移脚本按引入它们的版本号组织到相应的文件夹中:spring-doc.cadn.net.cn

版本

本附录中讨论的许多数据库表都包含一个版本列。该列非常重要,因为 Spring Batch 在处理数据库更新时采用乐观锁策略。这意味着每次记录被“触碰”(即更新)时,版本列中的值都会递增一。当存储库回写保存值时,如果版本号已发生变化,则会抛出 OptimisticLockingFailureException,表明存在并发访问错误。此检查是必要的,因为即使不同的批处理作业可能运行在不同的机器上,它们也都使用相同的数据库表。spring-doc.cadn.net.cn

身份

BATCH_JOB_INSTANCEBATCH_JOB_EXECUTIONBATCH_STEP_EXECUTION 各自包含以 _ID 结尾的列。这些字段充当各自表的主键。 然而,它们并非由数据库生成的键。相反,它们是由独立的序列生成的。这是必要的,因为在将领域对象插入数据库后,需要将其分配的键设置回实际对象上,以便在 Java 中能够唯一标识它们。较新的数据库驱动程序(JDBC 3.0 及以上版本)支持通过数据库生成键来实现此功能。但是,为了不强制依赖该特性,这里使用了序列。每种模式的变体都包含以下形式的语句:spring-doc.cadn.net.cn

CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ;
CREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ;
CREATE SEQUENCE BATCH_JOB_INSTANCE_SEQ;

许多数据库厂商不支持序列。在这些情况下,会使用变通方案, 例如以下适用于 MySQL 的语句:spring-doc.cadn.net.cn

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_INSTANCE_SEQ (ID BIGINT NOT NULL) type=InnoDB;
INSERT INTO BATCH_JOB_INSTANCE_SEQ values(0);

在前述情况下,使用表来替代每个序列。Spring 核心类 MySQLMaxValueIncrementer 随后会递增该序列中的单列,以提供类似的功能。spring-doc.cadn.net.cn

BATCH_JOB_INSTANCE表格

BATCH_JOB_INSTANCE 表保存了与 JobInstance 相关的所有信息,并作为整体层次结构的顶层。以下通用 DDL 语句用于创建该表:spring-doc.cadn.net.cn

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
);

以下列表描述了表中的每一列:spring-doc.cadn.net.cn

  • JOB_INSTANCE_ID: 标识实例的唯一 ID。它也是主键。此列的值应可通过在 JobInstance 上调用 getId 方法获得。spring-doc.cadn.net.cn

  • VERSION: 查看 版本spring-doc.cadn.net.cn

  • JOB_NAME: 从 Job 对象获取的作业名称。由于需要用于标识实例,因此该值不能为 null。spring-doc.cadn.net.cn

  • JOB_KEY: JobParameters 的序列化,用于唯一标识同一作业的不同实例。(具有相同作业名称的 JobInstances 必须拥有不同的 JobParameters,因此其 JOB_KEY 值也不同)。spring-doc.cadn.net.cn

BATCH_JOB_EXECUTION_PARAMS表格

BATCH_JOB_EXECUTION_PARAMS 表保存了与 JobParameters 对象相关的所有信息。它包含零个或多个传递给 Job 的键/值对,并作为作业运行参数的记录。对于每个有助于生成作业标识的参数,IDENTIFYING 标志将被设置为 true。请注意,该表已去规范化。无需为每种类型创建单独的表,而是使用一个表并通过某一列来指示类型,如下所示:spring-doc.cadn.net.cn

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)
);

以下列表描述了每一列:spring-doc.cadn.net.cn

请注意,此表没有主键。这是因为框架不需要主键,因此也不要求它。如果有需要,您可以添加一个由数据库生成的主键,而不会对框架本身造成任何问题。spring-doc.cadn.net.cn

BATCH_JOB_EXECUTION表格

BATCH_JOB_EXECUTION 表保存了与 JobExecution 对象相关的所有信息。每次运行 Job 时,都会创建一个名为 JobExecution 的新条目,并在此表中新增一行。以下列表展示了 BATCH_JOB_EXECUTION 表的定义:spring-doc.cadn.net.cn

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)
) ;

以下列表描述了每一列:spring-doc.cadn.net.cn

  • JOB_EXECUTION_ID: 唯一标识此执行的主键。该列的值可通过调用 JobExecution 对象的 getId 方法获得。spring-doc.cadn.net.cn

  • VERSION: 查看 版本spring-doc.cadn.net.cn

  • JOB_INSTANCE_ID: 来自 BATCH_JOB_INSTANCE 表的外键。它表示此执行所属的实例。每个实例可能包含多个执行。spring-doc.cadn.net.cn

  • CREATE_TIME: 表示执行创建时间的时间戳。spring-doc.cadn.net.cn

  • START_TIME:表示执行开始时间的时间戳。spring-doc.cadn.net.cn

  • END_TIME:表示执行完成时间的时间戳,无论成功还是失败。如果作业当前未运行且该列为空值,则表明发生了某种错误,框架在失败前无法执行最后一次保存。spring-doc.cadn.net.cn

  • STATUS: 表示执行状态的字符串。这可能是 COMPLETEDSTARTED 等。该列的对象表示形式是 BatchStatus 枚举。spring-doc.cadn.net.cn

  • EXIT_CODE:表示执行退出代码的字符串。在命令行作业的情况下,这可能被转换为数字。spring-doc.cadn.net.cn

  • EXIT_MESSAGE: 表示作业退出详细情况的字符串。在失败的情况下,这可能包含尽可能多的堆栈跟踪信息。spring-doc.cadn.net.cn

  • LAST_UPDATED: 表示此执行上次被持久化的时间戳。spring-doc.cadn.net.cn

BATCH_STEP_EXECUTION表格

BATCH_STEP_EXECUTION 表保存了与 StepExecution 对象相关的所有信息。该表在许多方面类似于 BATCH_JOB_EXECUTION 表,并且对于创建的每个 JobExecution,每个 Step 至少有一条条目。以下列表展示了 BATCH_STEP_EXECUTION 表的定义:spring-doc.cadn.net.cn

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)
) ;

以下列表描述了每一列:spring-doc.cadn.net.cn

  • STEP_EXECUTION_ID: 唯一标识此执行的主键。该列的值应通过调用 StepExecution 对象的 getId 方法获得。spring-doc.cadn.net.cn

  • VERSION: 查看 版本spring-doc.cadn.net.cn

  • STEP_NAME: 此执行所属的步骤名称。spring-doc.cadn.net.cn

  • JOB_EXECUTION_ID: 来自 BATCH_JOB_EXECUTION 表的外键。它表示此 StepExecution 所属的 JobExecution。对于给定的 Step 名称,每个 JobExecution 只能有一个 StepExecutionspring-doc.cadn.net.cn

  • START_TIME:表示执行开始时间的时间戳。spring-doc.cadn.net.cn

  • END_TIME:表示执行完成时间的时间戳,无论成功还是失败。即使作业当前未运行,此列中的空值也表明发生了某种类型的错误,且框架在失败前无法执行最后一次保存。spring-doc.cadn.net.cn

  • STATUS: 表示执行状态的字符串。这可能是 COMPLETEDSTARTED 等。该列的对象表示形式是 BatchStatus 枚举。spring-doc.cadn.net.cn

  • COMMIT_COUNT:在此执行过程中,步骤提交事务的次数。spring-doc.cadn.net.cn

  • READ_COUNT:本次执行中读取的项目数量。spring-doc.cadn.net.cn

  • FILTER_COUNT: 本次执行中过滤掉的项目数量。spring-doc.cadn.net.cn

  • WRITE_COUNT:此次执行中写入并提交的项目数量。spring-doc.cadn.net.cn

  • READ_SKIP_COUNT:本次执行期间读取时跳过的项目数量。spring-doc.cadn.net.cn

  • WRITE_SKIP_COUNT:本次执行期间在写入时跳过的项目数量。spring-doc.cadn.net.cn

  • PROCESS_SKIP_COUNT:本次执行过程中处理时跳过的项目数量。spring-doc.cadn.net.cn

  • ROLLBACK_COUNT:此次执行期间发生回滚的次数。请注意,此计数包含每次发生回滚的情况,包括重试过程中的回滚以及跳过恢复程序中的回滚。spring-doc.cadn.net.cn

  • EXIT_CODE:表示执行退出代码的字符串。在命令行作业的情况下,这可能被转换为数字。spring-doc.cadn.net.cn

  • EXIT_MESSAGE: 表示作业退出详细情况的字符串。在失败的情况下,这可能包含尽可能多的堆栈跟踪信息。spring-doc.cadn.net.cn

  • LAST_UPDATED: 表示此执行上次被持久化的时间戳。spring-doc.cadn.net.cn

BATCH_JOB_EXECUTION_CONTEXT表格

BATCH_JOB_EXECUTION_CONTEXT 表保存了与 JobExecutionContext 相关的所有信息。每个 JobExecution 恰好有一个 Job ExecutionContext,其中包含了特定作业执行所需的所有作业级数据。这些数据通常代表在发生故障后必须检索的状态,以便 JobInstance 能够“从中断处继续”。以下列表展示了 BATCH_JOB_EXECUTION_CONTEXT 表的定义:spring-doc.cadn.net.cn

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)
) ;

以下列表描述了每一列:spring-doc.cadn.net.cn

BATCH_STEP_EXECUTION_CONTEXT表格

BATCH_STEP_EXECUTION_CONTEXT 表保存了与 StepExecutionContext 相关的所有信息。每个 StepExecution 恰好有一个 ExecutionContext,它包含了特定步骤执行需要持久化的所有数据。这些数据通常代表在发生故障后必须检索的状态,以便 JobInstance 能够“从中断处继续”。以下列表展示了 BATCH_STEP_EXECUTION_CONTEXT 表的定义:spring-doc.cadn.net.cn

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)
) ;

以下列表描述了每一列:spring-doc.cadn.net.cn

归档

由于每次运行批处理作业时都会在多个表中生成条目,因此通常为元数据表创建归档策略。这些表本身旨在记录过去发生的情况,通常不会影响任何作业的运行,但有一些与重启相关的显著例外情况:spring-doc.cadn.net.cn

  • 该框架使用元数据表来确定特定的 JobInstance 是否之前已运行过。如果已运行且作业不可重启,则会抛出异常。spring-doc.cadn.net.cn

  • 如果 JobInstance 的条目在未成功完成的情况下被移除,框架会认为该作业是新的,而不是重启。spring-doc.cadn.net.cn

  • 如果作业被重新启动,框架会使用已持久化到ExecutionContext的任何数据来恢复Job’s的状态。因此,对于尚未成功完成的作业,从该表中删除任何条目将导致它们在再次运行时无法从正确的点开始。spring-doc.cadn.net.cn

国际和多字节字符

如果您在业务处理中使用多字节字符集(如中文或西里尔文),这些字符可能需要持久化到 Spring Batch 模式中。许多用户发现,只需将模式中的 VARCHAR 列长度加倍就足够了。另一些用户则倾向于使用 VARCHAR 列长度的一半值,通过 max-varchar-length 来配置 JobRepository。还有一些用户报告称,他们在模式定义中使用 NVARCHAR 替代了 VARCHAR。最佳结果取决于数据库平台以及数据库服务器的本地配置方式。spring-doc.cadn.net.cn

索引元数据表的建议

Spring Batch 为核心 jar 文件中的元数据表提供了针对多种常见数据库平台的 DDL 示例。该 DDL 中未包含索引声明,因为用户如何建立索引存在太多变数,这取决于其具体的平台、本地规范以及作业运行业务需求。下表旨在说明 Spring Batch 提供的 DAO 实现将在 WHERE 子句中使用哪些列,以及它们的使用频率,以便各个项目自行决定索引策略:spring-doc.cadn.net.cn

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

默认表名spring-doc.cadn.net.cn

Where 子句spring-doc.cadn.net.cn

频率spring-doc.cadn.net.cn

BATCH_JOB_INSTANCEspring-doc.cadn.net.cn

JOB_NAME = ? and JOB_KEY = ?spring-doc.cadn.net.cn

每次启动作业时spring-doc.cadn.net.cn

BATCH_JOB_EXECUTIONspring-doc.cadn.net.cn

JOB_INSTANCE_ID = ?spring-doc.cadn.net.cn

每次重新启动作业时spring-doc.cadn.net.cn

BATCH_STEP_EXECUTIONspring-doc.cadn.net.cn

VERSION = ?spring-doc.cadn.net.cn

在提交间隔(也称为块)以及步骤的开始和结束时spring-doc.cadn.net.cn

BATCH_STEP_EXECUTIONspring-doc.cadn.net.cn

STEP_NAME = ? and JOB_EXECUTION_ID = ?spring-doc.cadn.net.cn

每次步骤执行之前spring-doc.cadn.net.cn