flyway實作java 自動升級SQL腳本
為什么要用Flyway
在日常開發中,我們經常會遇到下面的問題:
-
自己寫的SQL忘了在所有環境執行;
-
別人寫的SQL我們不能確定是否都在所有環境執行過了;
-
有人修改了已經執行過的SQL,期望再次執行;
-
需要新增環境做資料遷移;
-
每次發版需要手動控制先發DB版本,再發布應用版本;
-
其它場景...
由于專案需求的變化,或者前期設計缺陷,導致在后期需要修改資料庫,這應該是一個比較常見的事情,如果專案還沒上線,你可能把表洗掉了重新創建,但是如果專案已經上線了,就不能這樣簡單粗暴了,每次運維部署專案,還得手動執行一遍SQL檔案,我們需要通過 SQL 腳本在已有資料表的基礎上進行升級,
有了flyway,這些問題都能得到很好的解決,
使用了 Flyway 之后,如果再想進行資料庫版本升級,就不用該以前的資料庫腳本了,直接創建新的資料庫腳本,專案在啟動時檢測了有新的更高版本的腳本,就會自動執行,這樣,在和其他同事配合作業時,也會方便很多,因為正常我們都是從 Git 上拉代碼下來,不拉資料庫腳本,這樣要是有人更新了資料庫,其他同事不一定能夠收到最新的通知,使用了 Flyway 就可以有效避免這個問題了,
所有的腳本,一旦執行了,就會在 flyway_schema_history 表中有記錄,如果你不小心搞錯了,可以手動從 flyway_schema_history 表中洗掉記錄,然后修改 SQL 腳本后再重新啟動(生產環境不建議),
Flyway是如何作業的
Flyway作業流程如下:
1、專案啟動,應用程式完成資料庫連接池的建立后,Flyway自動運行,
2、初次使用時,Flyway會創建一個flyway_schema_history表,用于記錄sql執行記錄,
3、Flyway會掃描專案指定路徑下(默認是classpath:db/migration)的所有sql腳本,與flyway_schema_history表腳本記錄進行比對,如果資料庫記錄執行過的腳本記錄,與專案中的sql腳本不一致,Flyway會報錯并停止專案執行,
4、如果校驗通過,則根據表中的sql記錄最大版本號,忽略所有版本號不大于該版本的腳本,再按照版本號從小到大,逐個執行其余腳本,
專案中使用Flyway
首先,在pom檔案中引入flyway的核心依賴包:
1、引入核心依賴包:
<dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> <version>5.2.4</version> </dependency>

這里使用5.2.4版本,經測驗7.0.0版本與目前我們使用的springboot版本有沖突,會導致flyway不執行,因此我們盡量不要使用高版本的flyway,
2、組態檔:
簡單配置一個屬性即可使用
# flyway 配置
spring:
flyway:
# 啟用或禁用 flyway
enabled: true
# flyway 的 clean 命令會洗掉指定 schema 下的所有 table, 生產務必禁掉,這個默認值是 false 理論上作為默認配置是不科學的,
clean-disabled: true
# SQL 腳本的目錄,多個路徑使用逗號分隔 默認值 classpath:db/migration
locations: classpath:db/migration
# metadata 版本控制資訊表 默認 flyway_schema_history
table: flyway_schema_history
# 如果沒有 flyway_schema_history 這個 metadata 表, 在執行 flyway migrate 命令之前, 必須先執行 flyway baseline 命令
# 設定為 true 后 flyway 將在需要 baseline 的時候, 自動執行一次 baseline,
baseline-on-migrate: true
# 指定 baseline 的版本號,默認值為 1, 低于該版本號的 SQL 檔案, migrate 時會被忽略
baseline-version: 1
# 字符編碼 默認 UTF-8
encoding: UTF-8
# 是否允許不按順序遷移 開發建議 true 生產建議 false
out-of-order: false
# 需要 flyway 管控的 schema list,這里我們配置為flyway 預設的話, 使用spring.datasource.url 配置的那個 schema,
# 可以指定多個schema, 但僅會在第一個schema下建立 metadata 表, 也僅在第一個schema應用migration sql 腳本.
# 但flyway Clean 命令會依次在這些schema下都執行一遍. 所以 確保生產 spring.flyway.clean-disabled 為 true
schemas: flyway
# 執行遷移時是否自動呼叫驗證 當你的 版本不符合邏輯 比如 你先執行了 DML 而沒有 對應的DDL 會拋出例外
validate-on-migrate: true
flyway的properties配置清單(屬性未測驗):
# 對執行遷移時基準版本的描述.
flyway.baseline-description
#當遷移時發現目標schema非空,而且帶有沒有元資料的表時,是否自動執行基準遷移,默認false.
flyway.baseline-on-migrate =false
#開始執行基準遷移時對現有的schema的版本打標簽,默認值為1.
flyway.baseline-version=1
#檢查遷移腳本的位置是否存在,默認false.
flyway.check-location=false
#當發現校驗錯誤時是否自動呼叫clean,默認false.
flyway.clean-on-validation-error=false
#是否開啟flywary,默認true.
flyway.enabled=true
#設定遷移時的編碼,默認UTF-8.
flyway.encoding
#當讀取元資料表時是否忽略錯誤的遷移,默認false.
flyway.ignore-failed-future-migration
#當初始化好連接時要執行的SQL.
flyway.init-sqls
#遷移腳本的位置,默認db/migration.
flyway.locations
#是否允許無序的遷移,默認false.
flyway.out-of-order
#目標資料庫的密碼.
flyway.password
#設定每個placeholder的前綴,默認${.
flyway.placeholder-prefix
#是否要被替換,默認true.
flyway.placeholder-replacementplaceholders
#設定每個placeholder的后綴,默認}.
flyway.placeholder-suffix
#設定placeholder的value
flyway.placeholders.[placeholder name]
#設定需要flywary遷移的schema,大小寫敏感,默認為連接默認的schema.
flyway.schemas
#遷移檔案的前綴,默認為V.
flyway.sql-migration-prefix
#遷移腳本的檔案名分隔符,默認__
flyway.sql-migration-separator
#遷移腳本的后綴,默認為.sql
flyway.sql-migration-suffix
#使用的元資料表名,默認為schema_version
flyway.tableflyway
#遷移時使用的目標版本,默認為latest version
flyway.target
#遷移時使用的JDBC URL,如果沒有指定的話,將使用配置的主資料源
flyway.url
#遷移資料庫的用戶名
flyway.user
#遷移時是否校驗,默認為true
flyway.validate-on-migrate
flyway的yml配置清單(已測驗,沒問題,推薦使用yml格式的組態檔)
# flyway 配置
spring:
flyway:
# 啟用或禁用 flyway
enabled: true
# flyway 的 clean 命令會洗掉指定 schema 下的所有 table, 生產務必禁掉,這個默認值是 false 理論上作為默認配置是不科學的,
clean-disabled: true
# SQL 腳本的目錄,多個路徑使用逗號分隔 默認值 classpath:db/migration
locations: classpath:db/migration
# metadata 版本控制資訊表 默認 flyway_schema_history
table: flyway_schema_history
# 如果沒有 flyway_schema_history 這個 metadata 表, 在執行 flyway migrate 命令之前, 必須先執行 flyway baseline 命令
# 設定為 true 后 flyway 將在需要 baseline 的時候, 自動執行一次 baseline,
baseline-on-migrate: true
# 指定 baseline 的版本號,默認值為 1, 低于該版本號的 SQL 檔案, migrate 時會被忽略
baseline-version: 1
# 字符編碼 默認 UTF-8
encoding: UTF-8
# 是否允許不按順序遷移 開發建議 true 生產建議 false
out-of-order: false
# 需要 flyway 管控的 schema list,這里我們配置為flyway 預設的話, 使用spring.datasource.url 配置的那個 schema,
# 可以指定多個schema, 但僅會在第一個schema下建立 metadata 表, 也僅在第一個schema應用migration sql 腳本.
# 但flyway Clean 命令會依次在這些schema下都執行一遍. 所以 確保生產 spring.flyway.clean-disabled 為 true
schemas: flyway
# 執行遷移時是否自動呼叫驗證 當你的 版本不符合邏輯 比如 你先執行了 DML 而沒有 對應的DDL 會拋出例外
validate-on-migrate: true
spring.flyway.clean-disabled:這個屬性非常關鍵,它表示是否要清除已有庫下的表,如果執行的腳本是 V1__xxx.sql,那么會先清除已有庫下的表,然后再執行腳本,這在開發環境下還挺方便,但是在生產環境下就要命了,而且它默認就是要清除,生產環境一定要自己配置設定為 true,
3、創建db/migration
因為flyway默認是讀取resources/db/migration下的檔案夾,如果我們需要修改這個路徑,可以在組態檔中實作

4、撰寫sql檔案
此處的SQL陳述句命名需要遵從一定的規范,否則運行的時候flyway會報錯,命名規則主要有兩種:
-
僅需要被執行一次的SQL命名以大寫的"V"開頭,后面跟上"0~9"數字的組合,數字之間可以用“.”或者下劃線"_"分割開,然后再以兩個下劃線 __ 分割,其后跟檔案名稱,最后以.sql結尾,比如,
V20210707__create_user.sql、V20210707__add_user.sql, -
可重復運行的SQL,則以大寫的“R”開頭,后面再以兩個下劃線分割,其后跟檔案名稱,最后以.sql結尾,,比如,
R__truncate_user_dml.sql,
其中,V開頭的SQL執行優先級要比R開頭的SQL優先級高,
V:固定大寫
20210707.01:20210707是日期,后面用.01代表序號
因為flyway的執行是有個順序的,比如你執行了V2021__create_user,又執行V2020_update_user,就會報錯,原因就是2020<2021,所以我們要保證序號是依次增大,
Flyway 是如何比較兩個 SQL 檔案的先后順序呢?它采用 采用左對齊原則, 缺位用 0 代替 ,舉幾個例子:
1.0.1.1 比 1.0.1 版本高,
?
1.0.10 比 1.0.9.4 版本高,
?
1.0.10 和 1.0.010 版本號一樣高, 每個版本號部分的前導 0 會被忽略,
__:這個是兩個 _
create_user是一個簡單的sql描述
.sql:以.sql結尾的檔案后綴是約定





我們只要在資料庫中創建flyway這個資料庫,啟動專案,flyway就會執行sql檔案,創建user表,并且會自動生成一個flyway_schema_history表

從這段啟動日志中,我們可以看到 Flyway 的執行資訊,資料庫腳本的執行執行,同時這里還說了,Flyway 還給創建了一個 flyway_schema_history 表,這個表用來記錄資料庫的更新歷史,

flyway_schema_history里面會去記錄sql檔案的執行記錄,每次啟動專案,都會去flyway_schema_history看sql是否執行過,如果沒有執行過,說明這個sql是新的sql,就會自動執行,并且記錄到表里面,

有了這條記錄,下次再啟動專案,V20210707.01、V20210707.02、V20210708.01 這個三個腳本檔案就不會執行了,因為系統知道這個腳本已經執行過了,如果你還想讓這些腳本再執行一遍,需要手動洗掉 flyway_schema_history 表中的對應記錄,那么專案啟動時,這個腳本就會被執行了,
R開頭的檔案和V開頭的檔案略有不同,R開頭的檔案只要發送修改,都會執行一遍,V開頭的檔案如果執行過一般,在發送修改,就會報錯,為了控制版本,我們盡量使用V開頭的檔案,這樣我們也可以很清楚的看到每個版本中的sql檔案,
常見問題
問題1
flyway遇到的問題Caused by: java.lang.ClassNotFoundException: org.flywaydb.core.api.callback.FlywayCallbac
原因:springboot版本和flyway版本不一致,一般是flyway版本過高,
解決辦法:將flyway的版本降到5.2.4就ok了
問題2
springboot 整合flyway 但是不生效,flyway不會自動執行sql
原因:如上
原因2:專案中沒有配置資料庫,沒有引入sq依賴或者配置
解決辦法:如上
解決辦法2:引入sql依賴,在yml檔案中配置sql資訊
問題3
flyway出錯 FlywayException: Validate failed: Detected failed migration to version
原因:sql腳本和資料庫中有沖突,需要檢查sql腳本哪里錯了,簡單的說就是V開頭的sql檔案,已經執行過了,在 flyway_schema_history 表里面有這個資料,但是你又改動了sql檔案,導致再次執行的時候報錯,
解決辦法:新建一個sql檔案,不要修改原來以V開頭的檔案或者在flyway_schema_history表中找到檔案相關執行記錄,刪掉重新執行,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/288977.html
標籤:Java
