附录 A:元数据模式

概述

Spring Batch 元数据表与在 Java 中表示它们的域对象非常匹配。例如,JobInstanceJobExecutionJobParameters和分别StepExecution 映射到BATCH_JOB_INSTANCEBATCH_JOB_EXECUTIONBATCH_JOB_EXECUTION_PARAMSBATCH_STEP_EXECUTIONExecutionContext映射到 BATCH_JOB_EXECUTION_CONTEXTBATCH_STEP_EXECUTION_CONTEXT。这JobRepository负责将每个 Java 对象保存并存储到其正确的表中。本附录详细描述了元数据表,以及创建它们时做出的许多设计决策。在查看下面的各种表创建语句时,重要的是要意识到所使用的数据类型尽可能通用。Spring Batch 提供了许多模式作为示例,由于各个数据库供应商处理数据类型的方式不同,所有这些模式都具有不同的数据类型。下图显示了所有 6 个表的 ERD 模型及其相互关系:

Spring Batch 元数据 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_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表包含与 a 相关的所有信息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。它也是主键。该列的值应该可以通过调用getIdon 方法获得 JobInstance

  • VERSION: 见版本

  • JOB_NAME:从Job对象中获取的作业名称。因为需要标识实例,所以不能为空。

  • JOB_KEY: 的序列化JobParameters,唯一标识同一作业的不同实例。(JobInstances具有相同的作业名称必须具有不同JobParameters的,因此,不同的JOB_KEY值)。

BATCH_JOB_EXECUTION_PARAMS

该表包含与对象BATCH_JOB_EXECUTION_PARAMS相关的所有信息 。JobParameters它包含 0 个或多个传递给 a 的键/值对,Job并用作运行作业所用参数的记录。对于有助于生成作业标识的每个参数,该IDENTIFYING标志设置为 true。请注意,该表已被非规范化。不是为每种类型创建一个单独的表,而是有一个表,其中有一列指示类型,如下面的清单所示:

CREATE TABLE BATCH_JOB_EXECUTION_PARAMS  (
	JOB_EXECUTION_ID BIGINT NOT NULL ,
	TYPE_CD VARCHAR(6) NOT NULL ,
	KEY_NAME VARCHAR(100) NOT NULL ,
	STRING_VAL VARCHAR(250) ,
	DATE_VAL DATETIME DEFAULT NULL ,
	LONG_VAL BIGINT ,
	DOUBLE_VAL DOUBLE PRECISION ,
	IDENTIFYING CHAR(1) NOT NULL ,
	constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
	references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
);

以下列表描述了每一列:

  • JOB_EXECUTION_IDBATCH_JOB_EXECUTION表中的外键,指示参数条目所属的作业执行。请注意,每次执行可能存在多行(即键/值对)。

  • TYPE_CD:存储值类型的字符串表示形式,可以是字符串、日期、长整型或双精度型。因为类型必须是已知的,所以它不能为空。

  • KEY_NAME:参数键。

  • STRING_VAL:参数值,如果类型是字符串。

  • DATE_VAL:参数值,如果类型是日期。

  • LONG_VAL:参数值,如果类型是长的。

  • DOUBLE_VAL:参数值,如果类型是双精度。

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

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

BATCH_JOB_EXECUTION

该表包含与 对象BATCH_JOB_EXECUTION相关的所有信息。JobExecution每次Job运行 a 时,此表中总会有一个 newJobExecution和一个新行。以下清单显示了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,
  JOB_CONFIGURATION_LOCATION VARCHAR(2500) NULL,
  constraint JOB_INSTANCE_EXECUTION_FK foreign key (JOB_INSTANCE_ID)
  references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;

以下列表描述了每一列:

  • JOB_EXECUTION_ID:唯一标识此执行的主键。该列的值可以通过调用对象的getId方法获得JobExecution

  • 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条目始终至少有一个条目。以下清单显示了表的定义:StepJobExecutionBATCH_STEP_EXECUTION

CREATE TABLE BATCH_STEP_EXECUTION  (
  STEP_EXECUTION_ID BIGINT  PRIMARY KEY ,
  VERSION BIGINT NOT NULL,
  STEP_NAME VARCHAR(100) NOT NULL,
  JOB_EXECUTION_ID BIGINT NOT NULL,
  START_TIME TIMESTAMP NOT 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:唯一标识此执行的主键。该列的值应该可以通过调用对象的getId方法获得StepExecution

  • VERSION: 见版本

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

  • JOB_EXECUTION_ID:BATCH_JOB_EXECUTION表中的外键。它指示 JobExecutionthisStepExecution属于哪个。给定名称可能只有一个 StepExecutionJobExecutionStep名称。

  • 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

该表包含与 aBATCH_JOB_EXECUTION_CONTEXT相关的所有信息 。per 恰好有一个,它包含执行特定作业所需的所有作业级数据。此数据通常表示发生故障后必须检索的状态,以便 a可以“从上次中断的地方开始”。以下清单显示了表的定义:ExecutionContextJobJob ExecutionContextJobExecutionJobInstanceBATCH_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

该表包含与 aBATCH_STEP_EXECUTION_CONTEXT相关的所有信息 。per 恰好有一个,它包含执行特定步骤所需的所有数据。该数据通常表示发生故障后必须检索的状态,以便可以“从中断的地方开始”。以下清单显示了 表的定义:ExecutionContextStepExecutionContextStepExecutionJobInstanceBATCH_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 。如果它已运行并且作业不可重新启动,则会引发异常。

  • 如果 a 的条目在JobInstance未成功完成的情况下被删除,则框架认为该作业是新的,而不是重新启动。

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

国际和多字节字符

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

索引元数据表的建议

Spring Batch provides DDL samples for the metadata tables in the core jar file for several common database platforms. Index declarations are not included in that DDL, because there are too many variations in how users may want to index, depending on their precise platform, local conventions, and the business requirements of how the jobs are operated. The following below provides some indication as to which columns are going to be used in a WHERE clause by the DAO implementations provided by Spring Batch and how frequently they might be used, so that individual projects can make up their own minds about indexing:

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

JOB_NAME = ? and JOB_KEY = ?

Every time a job is launched

BATCH_JOB_EXECUTION

JOB_INSTANCE_ID = ?

每次重新启动作业时

BATCH_STEP_EXECUTION

版本 = ?

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

BATCH_STEP_EXECUTION

STEP_NAME = ? 和 JOB_EXECUTION_ID = ?

在每一步执行之前


1. see XML Configuration