Flyway 和 Liquibase 都是 Java 項目中常用的 DB migration 工具, 從使用簡便性看,Flyway 比 Liquibase 更簡單, 從 github 的 star 數量看, flyway 更受歡迎.
==============================
flyway 命令行工具和 maven 插件
==============================
對於 SpringBoot 項目開發, 其實不需要專門安裝 flyway 命令行工具和 maven 插件, SpringBoot 啟動就會自動執行 DB migrate 操作. 對於其他的 flyway 操作, 就需要使用命令行工具或 maven 插件了.
flyway 提供命令行工具, 常用的命令包括:
Clean: 刪除所有創建的數據庫對象, 包括用戶、表、視圖等. 注意不要在生產庫上執行 clean 操作.
Migrate: 對數據庫依次應用版本更改.
Info: 獲取目前數據庫的狀態. 那些遷移已經完成, 那些遷移待完成. 所有遷移的執行時間以及結果.
Validate: 驗證已 Apply 的腳本是否有變更, Flyway 的 Migration 默認先做 Validate.
Baseline: 根據現有的數據庫結構生成一個基准遷移腳本.
Repair: 修復命令盡量不要使用, 修復場景有: 1. 移除失敗的 migration 記錄. 2.已經應用的 SQL 腳本被修改, 我們想重新應用該 SQL 腳本.
maven 插件, 最新 maven 插件見 https://mvnrepository.com/artifact/org.flywaydb/flyway-maven-plugin
<plugin> <groupId>org.flywaydb</groupId> <artifactId>flyway-maven-plugin</artifactId> <version>4.0.3</version> </plugin>
maven插件命令, mvn flyway:migrate
==============================
Flyway 的工作原理
==============================
flyway 需要在 DB 中先創建一個 metdata 表 (缺省表名為 flyway_schema_history), 在該表中保存着每次 migration 的記錄, 記錄包含 migration 腳本的版本號和 SQL 腳本的 checksum 值. 當一個新的 SQL 腳本被掃描到后, Flyway 解析該 SQL 腳本的版本號, 並和 metadata 表已 apply 的的 migration 對比, 如果該 SQL 腳本版本更新的話, 將在指定的 DB 上執行該 SQL 文件, 否則跳過該 SQL 文件.
兩個 flyway 版本號的比較, 采用左對齊原則, 缺位用 0 代替. 舉例如下:
1.2.9.4 比 1.2.9 版本高.
1.2.10 比 1.2.9.4 版本高.
1.2.10 和 1.2.010 版本號一樣高, 每個版本號部分的前導 0 會被忽略.
Flyway SQL 文件可以分為兩類: Versioned 和 Repeatable.
Versioned migration 用於版本升級, 每個版本有唯一的版本號並只能 apply 一次.
Repeatable migration 是指可重復加載的 migration, 一旦 SQL 腳本的 checksum 有變動, flyway 就會重新應用該腳本. 它並不用於版本更新, 這類的 migration 總是在 versioned migration 執行之后才被執行.
默認情況下, Migration SQL的命名規則如下圖:
其中的文件名由以下部分組成,除了使用默認配置外,某些部分還可自定義規則.
prefix: 可配置,前綴標識,默認值 V 表示 Versioned, R 表示 Repeatable
version: 標識版本號, 由一個或多個數字構成, 數字之間的分隔符可用點.或下划線_
separator: 可配置, 用於分隔版本標識與描述信息, 默認為兩個下划線__
description: 描述信息, 文字之間可以用下划線或空格分隔
suffix: 可配置, 后續標識, 默認為.sql
flyway 的 metadata 表結果如下:
CREATE TABLE flyway_schema_history ( installed_rank INT NOT NULL, version VARCHAR(50), description VARCHAR(200) NOT NULL, type VARCHAR(20) NOT NULL, script VARCHAR(1000) NOT NULL, checksum INT, installed_by VARCHAR(100) NOT NULL, installed_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP, execution_time INT NOT NULL, success TINYINT(1) NOT NULL, PRIMARY KEY (installed_rank), INDEX flyway_schema_history_s_idx (success) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
==============================
pom.xml
==============================
spring-boot-starter-parent 包沒有使用最新的 2.0.5, 最新版總是導致 HikariPool 無法初始化, 所以選擇的版本是 2.0.4
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent>
flyway 其實僅依賴 spring-boot-starter-jdbc 包,
<dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
加上 spring-boot-maven-plugin , 可生成 fat jar.
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
==============================
application.properties 參數
==============================
## 設定 db source 屬性 spring.datasource.url=jdbc:mysql://localhost:3306/world spring.datasource.username=root spring.datasource.password=toor ## 設定 flyway 屬性 spring.flyway.cleanDisabled = true # flyway 的 clean 命令會刪除指定 schema 下的所有 table, 殺傷力太大了, 應該禁掉. spring.flyway.enabled = true # 啟用或禁用 flyway spring.flyway.locations =classpath:db/migration # 設定 SQL 腳本的目錄,多個路徑使用逗號分隔, 比如取值為 classpath:db/migration,filesystem:/sql-migrations spring.flyway.baselineOnMigrate=true # 如果指定 schema 包含了其他表,但沒有 flyway schema history 表的話, 在執行 flyway migrate 命令之前, 必須先執行 flyway baseline 命令. # 設置 spring.flyway.baseline-on-migrate 為 true 后, flyway 將在需要 baseline 的時候, 自動執行一次 baseline. spring.flyway.baselineVersion=1 # 指定 baseline 的版本號,缺省值為 1, 低於該版本號的 SQL 文件, migrate 的時候被忽略. #spring.flyway.encoding= # Encoding of SQL migrations (default: UTF-8) spring.flyway.table=flyway_schema_history_myapp # 設定 flyway 的 metadata 表名, 缺省為 flyway_schema_history spring.flyway.outOfOrder=true # 開發環境最好開啟 outOfOrder, 生產環境關閉 outOfOrder . #spring.flyway.schemas= # 需要 flyway 管控的 schema list, 缺省的話, 使用的時 dbsource.connection直連上的那個 schema, 可以指定多個schema, 但僅會在第一個schema下建立 metadata 表, 也僅在第一個schema應用migration sql 腳本. 但flyway Clean 命令會依次在這些schema下都執行一遍.
更多參數見 https://flywaydb.org/documentation/configfiles , 需要說明的是, 這些參數配到springboot2 項目中, 需要加上 spring. 前綴.
==============================
flyway 最佳實踐
==============================
1. SQL 的文件名
開發環境和生產環境的 migration SQL 不共用. 開發過程往往是多人協作開發, DB migration 也相對比較頻繁, 所以 SQL 腳本會很多. 而生產環境 DB migration 往往由 DBA 完成, 每次升級通常需要提交一個 SQL 腳本.
(1). 開發環境 SQL 文件建議采用時間戳作為版本號.
開發環境 SQL 文件建議采用時間戳作為版本號, 多人一起開發不會導致版本號爭用, 同時再加上生產環境的版本號, 這樣的話, 將來手工 merge 成生產環境 V1.2d migration 腳本也比較方便, SQL 文件示例:
V20180317.10.59__V1.2_Unique_User_Names.sql
V20180317.14.59__V1.2_Add_SomeTables.sql
(2). 生產環境 SQL 文件, 應該是手動 merge 開發環境的 SQL 腳本, 版本號按照正常的版本, 比如 V2.1.5_001__Unique_User_Names.sql
2. migration 后的SQL 腳本不應該再被修改.
3. spring.flyway.outOfOrder 取值 true /false
對於開發環境, 可能是多人協作開發, 很可能先 apply 了自己本地的最新 SQL 代碼, 然后發現其他同事早先時候提交的 SQL 代碼還沒有 apply, 所以 開發環境應該設置 spring.flyway.outOfOrder=true, 這樣 flyway 將能加載漏掉的老版本 SQL 文件; 而生產環境應該設置 spring.flyway.outOfOrder=false
4. 多個系統公用要 DB schema
很多時候多個系統公用一個 DB schema , 這時候使用 spring.flyway.table 為不同的系統設置不同的 metadata 表, 缺省為 flyway_schema_history
轉自:https://www.cnblogs.com/harrychinese/p/springboot_flyway.html