Spring Boot + Flyway 實現數據庫版本管理神器

知道的越多,不知道的就越多,業餘的像一棵小草!

編輯:業餘草
來源:https://www.xttblog.com/?p=5004

一、前言

Flyway 是一款開源的數據庫版本管理工具,它更傾向於規約優於配置的方式。Flyway 可以獨立於應用實現管理並跟蹤數據庫變更,支持數據庫版本自動升級,並且有一套默認的規約,不需要複雜的配置,Migrations 可以寫成 SQL 腳本,也可以寫在 Java 代碼中,不僅支持 Command Line 和 Java API,還支持 Build 構建工具和 Spring Boot 等,同時在分佈式環境下能夠安全可靠地升級數據庫,同時也支持失敗恢復等。

二、簡單介紹

# 2.1 主要特性

  • 普通 SQL:純 SQL 腳本(包括佔位符替換)沒有專有的XML格式,沒有鎖定

  • 無限制:使用 Java 代碼來進行一些高級數據操作

  • 零依賴:只需運行在 Java6(及以上)和數據庫所需的 JDBC 驅動

  • 約定優於配置:遷移時,自動查找系統文件和類路徑中的 SQL 文件或 Java 類

  • 高可靠性:在集羣環境下進行數據庫升級是安全可靠的

  • 雲支持:完全支持 Microsoft SQL Azure, Google Cloud SQL & App Engine、Heroku Postgres 和 Amazon RDS

  • 自動遷移:使用 Flyway 提供的 API,讓應用啓動和遷移同時工作

  • 快速失敗:損壞的數據庫或失敗的遷移可以防止應用程序啓動

  • 數據庫清理:在一個數據庫中刪除所有的表、視圖、觸發器,而不是刪除數據庫本身

# 2.2 運行原理

當 Flyway 連接數據庫中的 schema 後,會先檢查是否已存在 flyway_schema_history 表,如果沒有則創建。該表用於跟蹤數據庫的狀態,如數據遷移的版本,遷移成功狀態等信息。

當 flyway_schema_history 存在後,Flyway 會掃描文件系統或應用中的 classpath 目錄的數據遷移文件,然後根據它們的版本號進行按序遷移,如下圖:

flyway_schema_history 表記錄的內容如下:

由於 flyway_schema_history 表中記錄了遷移的版本號,如果文件的版本號小於或等於標記爲當前版本的版本號,則忽略它們不執行。

上邊描述的內容或許對讀者來說還不夠直觀,那麼下面我們就開始進行實戰演練。

三、實戰

測試環境:Mysql5.7

新建一個 Maven 項目。

# 3.1 添加依賴

<!-- flyway -->
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
    <version>5.2.4</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.15</version>
</dependency>

# 3.2 配置數據遷移文件

在項目的 src/main/resources 下創建 db/migration 目錄,該目錄下放置需要數據遷移的文件。

數據遷移文件名稱格式爲:V[version]__[name].sql

注意:名稱中[version]和[name]之間是兩個下劃線!

本次測試新建名爲 V1__Create_person_table.sql 的文件,內容如下:

create table PERSON (
    ID int not null,
    NAME varchar(100) not null
);

版本 1 數據遷移的內容是創建一張 PERSON 表。

# 3.3 編碼

public class FlywayTest {
    public static void main(String[] args) {
        String url = "jdbc:mysql://127.0.0.1:3306/flyway?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&rewriteBatchedStatements=true&useSSL=false&serverTimezone=GMT%2B8";
        String user = "root";
        String password = "tiger";
        Flyway flyway = Flyway.configure().dataSource(url, user, password).load();
        // 創建 flyway_schema_history 表
//        flyway.baseline();
        // 刪除 flyway_schema_history 表中失敗的記錄
//        flyway.repair();
        // 檢查 sql 文件
//        flyway.validate();
        // 執行數據遷移
        flyway.migrate();
        // 刪除當前 schema 下所有表
//        flyway.clean();
    }
}

執行結果如下圖:

圖中,數據庫 flyway 中創建了 flyway_schema_history 表和 PERSON 表,數據成功遷移到指定數據庫中。

當系統升級時又需要做數據遷移,我們只需在 db/migration 目錄下再放置新版本的 sql 文件即可。

比如,我們再新建一個名爲 V2__Add_people.sql 文件,內容如下:

insert into PERSON (ID, NAME) values (1, 'Axel');
insert into PERSON (ID, NAME) values (2, 'Mr. Foo');
insert into PERSON (ID, NAME) values (3, 'Ms. Bar');

版本 2 的數據遷移內容是往 PERSON 表中插入 3 條數據。

再次執行上邊的程序,演示效果圖如下:

四、Spring Boot 整合

# 4.1 添加依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
</dependency>

# 4.2 application.yml

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/flyway?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&rewriteBatchedStatements=true&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: tiger
  flyway:
    enabled: true
    # 禁止清理數據庫表
    clean-disabled: true
    # 如果數據庫不是空表,需要設置成 true,否則啓動報錯
    baseline-on-migrate: true
    # 與 baseline-on-migrate: true 搭配使用
    baseline-version: 0
    locations: 
      - classpath:db/migration/mysql(根據個人情況設置)

將需數據遷移的 sql 文件放置到 db/migration/mysql 目錄中,啓動 Spring Boot 項目即可運行 Flyway 進行數據遷移。

測試結果同上,此處不再張貼。

注意事項:

如果 flyway 不是項目初期引入,而是在數據庫已有表的情況下引入時必須設置 baseline-on-migrate: true,設置該配置啓動項目後,flyway 就會在數據庫中創建 flyway_schema_history 表,並且會往該表中插入一條 version = 1 的建表記錄,如果遷移數據有 V1__ 開頭的文件,掃描文件會忽略該文件不執行遷移,進而可能引發其他遷移數據出錯的問題。

以上邊的 2 個 sql 文件爲例進行演示,flyway 庫中已有一張 test 表,運行程序結果如下:

由於忽略了 V1__Create_person_table.sql ,庫中就不創建 PERSON 表,在遷移 V2__Add_people.sql 文件中的數據時必然失敗。

解決方案先刪除flyway_schema_history 表, 然後配置文件中設置 baseline-version: 0,或修改數據遷移文件版本名稱,最後再次啓動應用即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章