寫在前面
最近由於項目變更比較大,需要經常修改表結構,然后對應的測試,開發,生產環境數據庫均要修改,有時候一不小心就忘記修改某個環境下的數據庫了,
等出問題才發現表結構沒有更新,如果項目還沒上線,還可以把表刪除了重新創建,但是如果項目已經上線了,就不能這樣簡單粗暴了,我們需要通過 SQL 腳本
在已有數據表的基礎上進行升級。鑒於這種情況,於是決定尋找數據庫版本控制工具。
在Java這部分,對數據庫版本控制的主要有兩個工具:
- Flyway
- Liquibase
兩個工具各有千秋,但是核心功能都是數據庫的版本管理,這里主要來看 Flyway。就像我們使用 Git 來管理代碼版本一樣,Flyway 可以用來管理數據庫版本。
Flyway官網地址:https://flywaydb.org
1、Flyway是如何工作的
關於FlyWay工作原理,官網給出了具體的工作原理圖。官網原理圖地址:https://flywaydb.org/getstarted/how
這里簡單記錄一下,僅做備忘。
1.1 場景一:使用Flyway從無到有創建數據庫
Flyway用'schema_version_history'數據表存放數據庫schema的歷史記錄,跟蹤數據庫結構的變更;
由於剛開始數據庫為空,Flyway找不到schema_version_history數據表,所以Flyway找不到它,就在數據庫中創建了此表,
之后我們則需要在項目中定義Migration,通常用SQL或Java定義。
如下圖所示,Flyway在運行時會順序執行上圖中的Migration1和Migration 2來實現對數據庫的更新;同時'schema_version_history'表也會記錄下這兩次修改。
'schema_version_history'表記錄修改歷史。如下圖所示:
說明:
腳本文件名(對應flyway_schema_history表的script字段)定義規則:
常用格式如下:
$PREFIX$VERSION__$REMARK.$SUBFIX
說明:
$prefix 表示 前綴,可在配置中指定,默認為 V; $version 表示 版本號,版本號中也可以使用 . 或 _分隔,在解析時會將 _ 轉換為 . 再保存到flyway_schema_history表的version字段中; $remark 表示 備注,解析后會將這部分寫入到描述字段中; $subfix 表示 后綴,可在配置中指定,默認為 .sql ;
版本號與備注之前使用__分隔;
例如: V20200307_01__initial.sql
1.2 場景二:基於已有數據庫更新
在此場景下,Flyway仍然會遍歷項目中定義的各個Migration,並參照schema_version_history數據表,忽略版本號低於或等於當前版本的Migration,
剩下的就是Pending Migration(待處理遷移版本),然后按照版本號順序執行Pending Migration,如下圖所示:
'schema_version_history'表記錄修改歷史。如下圖所示:
因此,每當我們要對數據庫的DDL或者DML進行遷移時,就只需要定義一個更高版本的Migration。
2、Spring Boot整合 Flyway
這部分也可以參考官網使用指導,官網整合地址:https://flywaydb.org/documentation/plugins/springboot
2.1 整合步驟
2.1.1 在項目的pom文件中導入Flyway依賴,目前官網最新版本如下:
<dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> <version>6.3.0</version> </dependency>
2.1.2 在application.properties或者application.yml文件添加配置
# 說明,在spring boot 1.x中,屬性前綴為flyway,在spring boot 2.x中為spring.flyway,這里需要區分不同版本 Spring.flyway: # 到新的環境中數據庫中有數據,且沒有flyway_schema_history表時,是否執行遷移操作。
如果設置為false,在啟動時會報錯,並停止遷移;
如果設置為true,則生成history表並完成所有的遷移,要根據實際情況設置; baseline-on-migrate: false # 執行時標記的tag 默認為<<Flyway Baseline>> baseline-description: <<Flyway Baseline>> # 是否啟用flyway enabled: true # 檢測遷移腳本的路徑是否存在,如不存在,則拋出異常 check-location: true # 腳本位置 locations: classpath:db/migration # 在遷移時,是否校驗腳本,假設V1.0__初始.sql已經遷移過了,在下次啟動時會校驗該腳本是否有變更過,則拋出異常 validate-on-migrate: true 特別說明: 如果非空數據庫遷移,在目標數據庫中手動建flyway_schema_history表並手動寫入初始化的腳本記錄,
使flyway跳過最初的校驗即可,后續可以保證版本的統一;
2.1.3 創建遷移數據庫腳本文件
可以在項目模塊下的 resources 目錄下,手動創建 db/migration 目錄,然后在該目錄下創建數據庫腳本,數據庫腳本的命名方式可以參考上面的說明:
“腳本文件名(對應flyway_schema_history表的script字段)定義規則”,當然也可以看下面:
腳本文件名(對應flyway_schema_history表的script字段)定義規則:
常用格式如下:
$PREFIX$VERSION__$REMARK.$SUBFIX
說明:
$prefix 表示 前綴,可在配置中指定,默認為 V; $version 表示 版本號,版本號中也可以使用 . 或 _分隔,在解析時會將 _ 轉換為 . 再保存到flyway_schema_history表的version字段中; $remark 表示 備注,解析后會將這部分寫入到描述字段中; $subfix 表示 后綴,可在配置中指定,默認為 .sql ;
版本號與備注之前使用__分隔;
例如: V20200307_01__initial.sql
完成這些之后,在數據庫中創建一個空的目標數據庫,然后啟動項目進行驗證。
2.1.4 驗證
項目啟動有如下日志信息,表明校驗成功:
補充:
如果是在一個全新的項目中使用 Flyway,那么在新建一個 Spring Boot 項目時,就有 Flyway 的選項,只需要勾選即可,如下圖所示:
項目創建成功后,resources 目錄下也會多出來一個 db/migration 目錄,這個目錄用來存放數據庫腳本,如下圖所示: