简介
概述
数据库迁移是一项从实体 Bean 模型生成 DDL 的功能,它支持确定模型先前版本的diff
,并根据模型差异生成适当的 DDL 更改。
您应该使用 FlywayDb
、LiquiBase
或类似工具运行diff
DDL。未来,Ebean 可能内置支持来运行 DDL,因为它已经具备了大部分功能,并且可以解决开发人员工作流和 DDL 脚本排序方面的一些当前问题。
数据库迁移有 2 个输出文件
- 迁移模型 XML - 这具有模型的逻辑 diff,作为
apply
或pendingDrops
更改集 - 应用 SQL - 这是应用更改的 DDL 脚本
当 DbMigration 运行时,它将加载任何先前的迁移 xml,并将它们组合在一起以定义先前的模型,然后将其与现有的实体 Bean 进行比较。
待定删除
只有非破坏性更改包含在apply
中,而drop table
和drop column
之类的更改则放入pendingDrops
更改集中。
需要明确选择待定删除的更改才能进入迁移。
鉴于应用程序在集群环境中运行,待定删除通常需要至少落后于正常的应用更改 1 次迁移。此延迟可能是几分钟、几天,而某些删除可能永远不会运行。
迁移 xml
当 DbMigration 运行时,将确定模型的diff
并将其输出为迁移模型 xml 文档。此 diff 可以具有apply
更改或pendingDrops
更改。
从迁移apply
更改集中生成将应用的实际 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 = new DbMigration();
dbMigration.setPlatform(DbPlatformName.POSTGRES);
dbMigration.generateMigration();
然后生成一个迁移,将 dropsFor
设置为具有我们想要应用的未决的删除的迁移版本。此外,迁移应用 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.1
和 1_1
都转换为版本 1.1
。
请注意,版本编号控制迁移执行的顺序,并遵循语义版本控制,因此,例如 1.1.1
将在 1.2
之前执行。通过这种方式,我们可以添加“补丁”迁移。
工作流
如果您使用 Ebean 的迁移运行器执行迁移,请注意,要运行迁移,要求必须已经运行了以前的迁移
。这与 FlywayDB 略有不同,后者需要严格的版本号顺序(或者我们可以禁用它以允许任何顺序)。
如果您使用类似于“git flow”的工作流,那么 Ebean 的迁移运行器允许您以非严格顺序处理合并请求。为此工作的假设是,在有 2 个或更多合并请求(正在审查,尚未合并到公共 DEV 分支中)的情况下,不会有冲突的数据库迁移更改(如果存在,Ebean 将允许迁移运行,但迁移本身会出错)。
迁移版本和名称
对于迁移,开发人员需要提供 version
和 name
,这些可以通过环境变量、系统属性、ebean.properties 或以编程方式设置。
System.setProperty("ddl.migration.version", "1.1");
System.setProperty("ddl.migration.name", "support end dating");
启动时生成迁移
当 Ebean 实例启动时,可以通过将 ddl.migration.generate
系统属性或环境变量设置为 true 来生成数据库迁移。
@Test
public void generate() {
System.setProperty("ddl.migration.generate", "true");
System.setProperty("ddl.migration.version", "1.1");
System.setProperty("ddl.migration.name", "support end dating");
// migration will be generated when Ebean starts
// ... typically by running your application.
DB.getDefault();
}
离线生成
我们可以在不启动应用程序的情况下以编程方式生成迁移。在 src/test/java
中使用 main 方法
添加以下代码。
运行此 main 方法将生成下一个迁移并以 离线模式
启动 Ebean。此离线模式意味着我们不需要启动应用程序或需要数据库来生成迁移。
package main;
import io.ebean.Platform;
import io.ebean.dbmigration.DbMigration;
import java.io.IOException;
/**
* Generate the DB Migration.
*/
public class MainDbMigration {
/**
* Generate the next "DB schema DIFF" migration.
* <p>
* These migration are typically run using FlywayDB, Liquibase
* or Ebean's own built in migration runner.
* </p>
*/
public static void main(String[] args) throws IOException {
// optionally specify the version and name
//System.setProperty("ddl.migration.version", "1.1");
System.setProperty("ddl.migration.name", "support end dating");
// generate a migration using drops from a prior version
//System.setProperty("ddl.migration.pendingDropsFor", "1.2");
DbMigration dbMigration = new DbMigration();
dbMigration.setPlatform(Platform.POSTGRES);
// generate the migration ddl and xml
// ... start in "offline" mode
dbMigration.generateMigration();
}
}
运行迁移
你可以使用 FlywayDb
、Liquibase
或 Ebean 自带的迁移运行器来运行迁移。
Ebean 的迁移运行器
## run migrations when the 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
,当 Ebean 启动时,它将查看迁移并运行任何需要运行的迁移。默认情况下,迁移运行器将创建一个名为 db_migration
的表,该表保存已运行迁移的元数据,并在成功执行迁移时将数据插入此表。
可重复迁移
可重复迁移是特殊迁移,以 R__
开头且没有版本号。如果可重复迁移尚未运行或其内容已更改(MD5 校验和已更改),则将运行可重复迁移。
可重复迁移可以包含任何 DDL,但对于 ORM,我们使用它们来定义 数据库视图
,例如使用 @View
将实体 Bean 映射到数据库视图而不是表。
请参阅展示使用 extra-ddl.xml 和 @View 的可重复迁移的第二个视频。
FlywayDB 注意事项
要与 FlywayDB 一起使用,目前我们需要使用 V
为“版本迁移”添加前缀,以便同时支持“版本迁移”和“可重复迁移”。为此
## must use V prefix on "version migrations" when using FlywayDB
## with both "version" and "repeatable" migrations
ebean.migration.applyPrefix=V