schema-appendix.md 16.2 KB
Newer Older
dallascao's avatar
dallascao 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
# 元数据模式

## [](#metaDataSchema)附录 A:元数据模式

### [](#metaDataSchemaOverview)概述

Spring 批处理元数据表与在 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 提供了许多模式作为示例,所有这些模式都具有不同的数据类型,这是由于各个数据库供应商处理数据类型的方式有所不同。下图显示了所有 6 个表及其相互关系的 ERD 模型:

![Spring Batch Meta-Data ERD](./images/meta-data-erd.png)

图 1。 Spring 批处理元数据 ERD

#### [](#exampleDDLScripts)示例 DDL 脚本

Spring 批处理核心 JAR 文件包含用于为许多数据库平台创建关系表的示例脚本(反过来,这些平台由作业存储库工厂 Bean 或等效的名称空间自动检测)。这些脚本可以按原样使用,也可以根据需要修改附加的索引和约束。文件名的形式为`schema-*.sql`,其中“\*”是目标数据库平台的简称。脚本在包`org.springframework.batch.core`中。

#### [](#migrationDDLScripts)迁移 DDL 脚本

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

* `2.2`:如果你从`2.2`之前的版本迁移到`2.2`版本,则包含所需的脚本

* `4.1`:如果你从`4.1`之前的版本迁移到`4.1`版本,则包含所需的脚本

#### [](#metaDataVersion)版本

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

#### [](#metaDataIdentity)恒等式

`BATCH_JOB_INSTANCE``BATCH_JOB_EXECUTION``BATCH_STEP_EXECUTION`都包含以`_ID`结尾的列。这些字段充当各自表的主键。然而,它们不是数据库生成的密钥。相反,它们是由单独的序列生成的。这是必要的,因为在将一个域对象插入到数据库中之后,需要在实际对象上设置给定的键,以便在 Java 中对它们进行唯一标识。较新的数据库驱动程序(JDBC3.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`然后在这个序列中增加一列,以便提供类似的功能。

### [](#metaDataBatchJobInstance)`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(2500)
);
```

下面的列表描述了表中的每个列:

* `JOB_INSTANCE_ID`:标识实例的唯一 ID。这也是主要的关键。可以通过调用`JobInstance`上的`getId`方法获得此列的值。

* `VERSION`:见[Version](#metaDataVersion)

* `JOB_NAME`:从`Job`对象获得的作业的名称。因为需要它来标识实例,所以它不能是空的。

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

### [](#metaDataBatchJobParams)`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 ,
	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_ID`:来自`BATCH_JOB_EXECUTION`表的外键,该外键指示参数项所属的作业执行。请注意,每个执行都可能存在多个行(即键/值对)。

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

* key\_name:参数键。

* string\_val:参数值,如果类型是 string。

* date\_val:参数值,如果类型是 date。

* long\_val:参数值,如果类型是 long。

* double\_val:参数值,如果类型是 double。

* 标识:标志,指示参数是否有助于相关的`JobInstance`的标识。

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

### [](#metaDataBatchJobExecution)`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,
  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`:唯一标识此执行的主键。通过调用`JobExecution`对象的`getId`方法,可以获得此列的值。

* `VERSION`:见[Version](#metaDataVersion)

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

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

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

* `END_TIME`:时间戳表示执行完成的时间,无论成功还是失败。当作业当前未运行时,此列中的空值表示发生了某种类型的错误,框架在失败之前无法执行最后一次保存。

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

* `EXIT_CODE`:表示执行的退出代码的字符串。在命令行作业的情况下,可以将其转换为数字。

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

* `LAST_UPDATED`:时间戳表示此执行最后一次被持久化的时间。

### [](#metaDataBatchStepExecution)`BATCH_STEP_EXECUTION`

批处理 \_step\_execution 表保存与`StepExecution`对象相关的所有信息。该表在许多方面与`BATCH_JOB_EXECUTION`表类似,并且对于每个创建的`JobExecution`,每个`Step`总是至少有一个条目。下面的清单显示了`BATCH_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`:唯一标识此执行的主键。可以通过调用`StepExecution`对象的`getId`方法获得此列的值。

* `VERSION`:见[Version](#metaDataVersion)

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

* `JOB_EXECUTION_ID`:来自`BATCH_JOB_EXECUTION`表的外键。它指示了`JobExecution`这个`StepExecution`所属的`JobExecution`。对于给定的`JobExecution`名称,可能只有一个`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`:时间戳表示此执行最后一次被持久化的时间。

### [](#metaDataBatchJobExecutionContext)`BATCH_JOB_EXECUTION_CONTEXT`

`BATCH_JOB_EXECUTION_CONTEXT`表包含与`Job``ExecutionContext`相关的所有信息。这里正好有一个`Job``ExecutionContext`per`JobExecution`,它包含特定作业执行所需的所有作业级别数据。该数据通常表示故障后必须检索的状态,因此`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`:整个上下文,序列化。

### [](#metaDataBatchStepExecutionContext)`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`:整个上下文,序列化。

### [](#metaDataArchiving)存档

由于每次运行批处理作业时,多个表中都有条目,因此通常需要为元数据表创建归档策略。这些表本身旨在显示过去发生的事情的记录,并且通常不会影响任何作业的运行,只有一些与重新启动有关的明显例外:

* 该框架使用元数据表来确定特定的`JobInstance`是否已经运行过。如果作业已经运行,并且不能重新启动,那么将抛出一个异常。

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

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

### [](#multiByteCharacters)国际和多字节字符

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

### [](#recommendationsForIndexingMetaDataTables)建立元数据表索引的建议

Spring 批处理为几个常见的数据库平台的核心 JAR 文件中的元数据表提供了 DDL 示例。索引声明不包含在该 DDL 中,因为用户可能希望索引的方式有太多的变化,这取决于他们的精确平台、本地约定以及作业如何操作的业务需求。下面的内容提供了一些指示,说明 Spring Batch 提供的 DAO 实现将在`WHERE`子句中使用哪些列,以及它们可能被使用的频率,以便各个项目可以就索引做出自己的决定:

|  Default Table Name  |              Where Clause               |频率|
|----------------------|-----------------------------------------|-------------------------------------------------------------------|
| BATCH\_JOB\_INSTANCE |     JOB\_NAME = ? and JOB\_KEY = ?      |每次有工作要做的时候|
|BATCH\_JOB\_EXECUTION |          JOB\_INSTANCE\_ID = ?          |每次重新启动作业时|
|BATCH\_STEP\_EXECUTION|               VERSION = ?               |在提交间隔上,a.k.a.chunk(以及<br/>步骤的开始和结束)|
|BATCH\_STEP\_EXECUTION|STEP\_NAME = ? and JOB\_EXECUTION\_ID = ?|在每一步执行之前|