数据库迁移简介

数据库迁移简介

可重复迁移

使用 @View、extra-ddl.xml 和可重复迁移

输出文件

数据库迁移有 2 个输出文件

  • 迁移模型 XML - 这具有模型的逻辑差异,作为 applypendingDrops 更改集
  • 应用 SQL - 这是应用更改的 DDL 脚本

当运行 DbMigration 时,它会加载任何先前的迁移 xml,并将它们组合在一起以定义先前的模型,然后将其与现有的实体 bean 进行比较。

待处理的删除

仅将非破坏性更改包含在 apply 中,而 drop tabledrop column 等更改则放入 pendingDrops changeSet 中。

需要明确选择待处理的删除更改才能进入迁移。

鉴于应用程序在集群环境中运行,待处理的删除通常需要至少 1 次迁移才能跟踪正常的应用更改。此延迟可能是几分钟、几天,并且某些删除可能永远不会运行。

迁移 xml

当运行 DbMigration 时,将确定模型的 diff 并将其输出为迁移模型 xml 文档。此差异可以有 apply 更改或 pendingDrops 更改。

从迁移 apply changeSet 中生成将应用的实际 DDL。

逻辑更改

请注意,迁移 xml 中的更改与数据库无关,并且可以将单个迁移 xml 文档用于为多个数据库生成迁移 DDL。例如,您可以从单个迁移 xml 为 Postgres、Oracle 和 SQL Server 生成迁移 DDL 脚本。在迁移 xml 中,您将看到逻辑类型,如 JSON 类型(在数据库中存储 JSON 文档),对于 Postgres,这可以转换为 JSONB,对于 Oracle,这可以转换为 CLOB。

更改在逻辑上也是“逻辑的”,因为对具有 @History 和 @Draftable 的实体所做的更改通常会转换为多个更改。例如,向 @History 实体添加属性可能会向基本表添加列,向历史记录表添加列,并根据需要更改触发器。

迁移 xml 示例

以下是使用 apply 更改生成的迁移 xml 示例。客户表已向其中添加了 2 个新列。

如果客户表具有 @History 支持,则这还可能向历史记录表添加列并更新关联的数据库触发器。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
  <changeSet type="apply">
    <addColumn tableName="customer">
      <column name="registered" type="date"/>
      <column name="comments" type="varchar(1000)"/>
    </addColumn>
  </changeSet>
</migration>

具有 pendingDrops 的迁移示例

以下是使用 pendingDrops 更改生成的迁移 xml 示例。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
  <changeSet type="pendingDrops">
    <dropColumn columnName="shortTitle" tableName="document" withHistory="true"/>
  </changeSet>
</migration>

除非显式选择,否则不会将待定删除更改合并到 apply DDL 脚本中。一旦应用了待定删除,它们就会从“待定删除”列表中删除。

应用 DDL

apply ddl 脚本包含我们要应用到数据库的更改。这是您让 FlywayDB 或类似工具运行的 DDL 脚本。

应用待处理的删除

INFO  c.a.ebean.dbmigration.DbMigration - Pending un-applied drops in versions [1.2]

数据库迁移将记录 INFO 级别消息,说明哪些迁移包含尚未应用的待定删除。在某个时间点,决定将其中一个待定删除作为下一个迁移应用。

// generate a migration as the drops from migration version "1.2"
System.setProperty("ddl.migration.pendingDropsFor", "1.2");

DbMigration dbMigration = DbMigration.create();
dbMigration.setPlatform(Platform.POSTGRES);
dbMigration.generateMigration();
// generate a migration as the drops from migration version "1.2"
System.setProperty("ddl.migration.pendingDropsFor", "1.2")

DbMigration.create().apply {
  setPlatform(Platform.POSTGRES)
}.generateMigration()

然后生成一个迁移,其中 dropsFor 设置为具有我们要应用的待定删除的迁移版本。此外,迁移 apply ddl 包含将执行的各种删除语句。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
  <changeSet type="apply" dropsFor="1.2">
    <dropColumn columnName="shortTitle" tableName="document" withHistory="true"/>
  </changeSet>
</migration>

版本格式

支持的“版本”编号格式与 FlywayDB 版本编号相同,您可以在其中使用“.”或“_”(句点或下划线)作为分隔符。

示例

因此,1.11_1 都转换为版本 1.1

请注意,版本编号控制了执行迁移的顺序,并遵循语义版本控制,因此,例如,1.1.1 将在 1.2 之前执行。通过这种方式,我们可以添加“补丁”迁移。

工作流

如果您使用 Ebean 的迁移运行器来执行迁移,请注意,要运行迁移,要求是必须运行了之前的迁移。这与 FlywayDB 略有不同,FlywayDB 要求严格的版本号顺序(或者我们可以禁用它以允许任何顺序)。

如果您使用类似于“git flow”的工作流,那么 Ebean 的迁移运行器允许您以非严格顺序处理合并请求。为此而做出的假设是,在存在 2 个或更多合并请求(正在审查,尚未合并到公共 DEV 分支中)的情况下,不会有冲突的数据库迁移更改(如果存在,Ebean 将允许迁移运行,但迁移本身会出错)。

迁移版本和名称

对于迁移,开发人员需要提供versionname,可以通过环境变量、系统属性或 ebean.properties 或以编程方式设置这些属性。

System.setProperty("ddl.migration.version", "1.1");
System.setProperty("ddl.migration.name", "support end dating");
System.setProperty("ddl.migration.version", "1.1")
System.setProperty("ddl.migration.name", "support end dating")

离线生成

我们可以在不启动应用程序的情况下以编程方式生成迁移。在src/test/java中添加带有main 方法的以下代码。

运行此 main 方法将生成下一个迁移并以offline 模式启动 Ebean。此离线模式意味着我们无需启动应用程序或需要数据库来生成迁移。

package main;

import io.ebean.annotation.Platform;
import io.ebean.dbmigration.DbMigration;
import java.io.IOException;

public class GenerateDbMigration {

  /**
   * Generate the next "DB schema DIFF" migration.
   */
  public static void main(String[] args) throws IOException {

    DbMigration dbMigration = DbMigration.create();
    dbMigration.setPlatform(Platform.POSTGRES);

    dbMigration.generateMigration();
  }
}
import io.ebean.annotation.Platform
import io.ebean.dbmigration.DbMigration

fun main() {
  DbMigration.create().apply {
    setPlatform(Platform.POSTGRES)
  }.generateMigration()
}

运行迁移

你可以使用FlywayDbLiquibase或 Ebean 自带的迁移运行器运行迁移。

Ebean 的迁移运行器

## run migrations when Ebean starts
ebean.migration.run=true

## optionally specify different DB credentials
## to run the migration (own the tables)
datasource.db.adminusername=myDbTableOwner
datasource.db.adminpassword=secret

如果ebean.migration.run=true,则当 EbeanServer 启动时,它将查看迁移并运行任何需要运行的迁移。默认情况下,迁移运行器将创建一个名为db_migration的表,该表保存已运行迁移的元数据,并在成功执行迁移时将数据插入此表。

可重复迁移

可重复迁移是特殊迁移,以R__开头,没有版本号。如果可重复迁移尚未运行或其内容已更改(MD5 校验和已更改),则将运行可重复迁移。

可重复迁移可以包含任何 DDL,但对于 ORM,我们使用它们来定义database VIEWS,例如使用@View将实体 bean 映射到数据库视图而不是表。

请参阅展示可重复迁移的第二个视频,其中包含 extra-ddl.xml,并与 @View 一起使用。

可重复迁移

使用 @View、extra-ddl.xml 和可重复迁移

FlywayDB 注意事项

要与 FlywayDB 一起使用,我们目前需要使用V为“版本迁移”添加前缀,以便同时支持“版本迁移”和“可重复迁移”。为此

## must use V prefix on "version migrations" when using FlywayDB
## with both "version" and "repeatable" migrations
ebean.migration.applyPrefix=V