[toc]
前言
我们在日常工作中通常遇到的大多数服务只是从用户那里获取一些输入并填充数据库,并从数据库中读取并在 UI 上显示。每个数据库都有一个Schema,我们会在需求发生变化时进行迭代过程,以修改我们的Schema。现在,所有这些迁移都可以单独驻留在应用程序中,并且可以由数据库团队处理,我们可以以版本控制的方式将此迁移脚本与应用程序一起保留,并在应用程序启动时应用它们,这就是flyway为我们所做的。
Flyway (https://flywaydb.org/documentation/) 是一个开源数据库迁移工具,用于迁移数据库Schema,它可以独立使用,并且与Spring启动有很好的集成。Liquibase 在数据库迁移的另一个选项中,大多数时候我们会看到这两个选项中的一个被用于生产服务,Flyway 支持很多的数据库,具体情况请查看文档以获取更多详细信息。
一、Flyway
Flyway 偏向于简单和约定俗成,而不是配置。
- 每个迁移脚本文件的格式为 V.sql
- 如果我们想撤消迁移,我们可以将该脚本放在文件名 U__.sql
- Flyway 还存储文件的校验和,一旦应用了文件,就无法更改内容。
- 它在名为 flyway_schema_history 的表中跟踪迁移历史记录
二、Spring Boot + Flyway
为了展示带有flyway的spring boot 案例,我将使用我们上一次创建的服务。我们的目的是开始创建一个schema,并且使用Flyway。为了将flyway与spring boot集成,我们首先将以下依赖项添加到我们的服务中:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
我们首先添加spring-boot-starter-data-jpa,这为我们的应用程序提供了jpa和hibernate 功能。当我们在这里使用 postgresql 时,我们需要添加 postgresql 驱动程序依赖项。最后我们需要添加flyway核心依赖性。
Flyway 使用 spring 数据源配置来查找数据库,将数据库的详细信息添加到我们的应用程序中。这里,我创建了一个名为 inventory 的数据库和一个名为 inventory_rw 的 R/W 用户,我们的应用程序配置如下所示:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/inventory
username: inventory_rw
password: '*****'
到目前为止,flyway知道要连接哪个数据库与哪些凭据,现在我们需要提供迁移脚本,我们将第一个迁移脚本命名为 V1__init.sql,如下所示 :
CREATE SCHEMA IF NOT EXISTS inv;
SET search_path TO inv,public;
CREATE TABLE IF NOT EXISTS products(
id UUID PRIMARY KEY,
product_name VARCHAR(255) NOT NULL,
stock NUMERIC NOT NULL default 0,
manufacturer VARCHAR(255) NOT NULL
);
现在,运行应用程序,我们看到一些日志如下:
uccessfully applied 1 migration to schema "public", now at version v1 (execution time 00:00.046s)
如果我们连接到我们的数据库,我们会看到以下内容:
查看公共Schema,flyway_schema_history 表也已创建:
表现在的样子为:
现在,让我们尝试更改迁移脚本,我们得到以下例外:
Caused by: org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation
Migration checksum mismatch for migration version 1
-> Applied to database : 2071614183
-> Resolved locally : 387884339. Either revert the changes to the migration, or run repair to update the schema history.
因此,一旦默认应用了您的架构,我们就无法更改脚本。但是,我们可以通过spring.flyway.validate-on-migrate=false禁用此检查。让我们在表格中添加一列。我们需要添加一个版本号大于上一个版本的新迁移脚本。让我们创建一个新的文件名V2_created_on_column.sql并添加以下脚本:
ALTER TABLE products ADD COLUMN created_on TIMESTAMP NOT NULL ;
日志如下:
Current version of schema "public": 1
Migrating schema "public" to version "2 - created on"
Successfully applied 1 migration to schema "public", now at version v2 (execution time 00:00.051s)
查看表视图:
三、已有数据库+Flyway
如果我们已经有一个不是使用 flyway 创建的数据库,并且公共模式中已经有其他表,我们将在下面看到例外。
Found non-empty schema(s) "public" but no schema history table. Use baseline() or set baselineOnMigrate to true to initialize the schema history table.
Flyway 拒绝在没有历史记录模式的非空数据库上迁移,为了解决这个问题,我们需要为Flyway提供一个基线。基线是一种告诉 flway 不关心此版本之前发生了什么,基于当前版本进行任何更改的方法。使用 spring config,我们可以向应用程序添加 below 属性来实现这一功能:
spring:
flyway:
baseline-on-migrate: true
baseline-version: '0'
现在,这里有一个小问题:如果您不提供要作为基线的版本,则提供的默认值为 1。在这里我提供了一个自定义值 0,以便应用我的脚本(如 V1 及以后)。schema历史记录表将如下所示:
现在,我们的架构历史记录表中有一个名为<>的新条目。
四、自定义用户
到目前为止,在我们的配置中,flyway 正在使用 spring 数据源中提供的用户。我们可以为flyway提供不同的用户,以下配置使用单独的 R/W 用户进行迁移:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/inventory
username: inventory_ro
password: '******'
flyway:
baseline-on-migrate: true
baseline-version: '0'
user: inventory_rw
password: '******'
Spring Boot 的 Flyway 集成有很多属性需要配置,例如我们可以定义自定义模式,flyway_schema_history将在哪里创建表、挑选迁移脚本、默认模式名称等。可以在 https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html 找到这些属性的列表。
小节
这就是这篇文章的内容,我们已经知道如何迭代数据库并使用 flyway 应用迁移。在下一篇文章中,我将展示如何将数据库与 Spring Boot 应用程序集成。