從零搭建開發(fā)腳手架 Spring Boot集成Flyway實(shí)現(xiàn)數(shù)據(jù)庫版本管理
- Flyway是什么
- Flyway集成和使用
- 添加依賴
- 配置文件
- 腳本
- 測試
- 原理
- 高級(jí)
- 基于Java的遷移回調(diào)
Flyway是什么
Flyway是一款數(shù)據(jù)庫版本控制管理工具,支持?jǐn)?shù)據(jù)庫版本自動(dòng)升級(jí)。
- 項(xiàng)目初始化的時(shí)候,往往都是要先手動(dòng)執(zhí)行數(shù)據(jù)庫腳本。
- 在開發(fā)過程當(dāng)中,數(shù)據(jù)結(jié)構(gòu)或者數(shù)據(jù)有更新時(shí),往往都要手動(dòng)執(zhí)行腳本同步開發(fā)環(huán)境、測試環(huán)境。
現(xiàn)在我們就可以使用flyway來幫我們自動(dòng)的去完成這個(gè)工作。
Flyway集成和使用
添加依賴
- <dependency>
- <groupId>org.flywaydb</groupId>
- <artifactId>flyway-core</artifactId>
- </dependency>
由于是Spring Boot項(xiàng)目集成,版本直接使用默認(rèn)的即可
配置文件
- spring:
- flyway:
- #是否開啟flyway,默認(rèn)true
- enabled: true
- #當(dāng)遷移時(shí)發(fā)現(xiàn)目標(biāo)schema非空,而且沒有元數(shù)據(jù)的表時(shí),(即迭代中項(xiàng)目)是否自動(dòng)執(zhí)行基準(zhǔn)遷移,默認(rèn)false.
- baseline-on-migrate: true
- # 是否允許無序運(yùn)行遷移, 默認(rèn)false,建議開發(fā)環(huán)境開啟,生成環(huán)境關(guān)閉
- out-of-order: true
- #設(shè)定SQL腳本的目錄,可以配置多個(gè),比如為classpath:db/migration,filesystem:/sql-migrations,默認(rèn)classpath:db/migration
- locations:
- - classpath:db/migration
更多參數(shù)見 https://flywaydb.org/documentation/configfiles
“這些參數(shù)配到springboot2 項(xiàng)目中, 需要加上 spring前綴
腳本
在resource目錄下面建立db.migration目錄,放置sql文件
sql腳本的格式:
- V/R+版本號(hào)+雙下劃線+描述+結(jié)束符:
- 例如:V20190429.1530__t_user_update.sql (開發(fā)環(huán)境:建議日期+時(shí)分秒)
- 例如:V1.1__init.sql(生產(chǎn)環(huán)境:建議把上面的腳步合并用版本號(hào))
測試
默認(rèn)情況下,Spring Boot在應(yīng)用程序啟動(dòng)時(shí)自動(dòng)運(yùn)行Flyway數(shù)據(jù)庫遷移。
結(jié)果如下:
注意:
Flyway社區(qū)版不支持MySQL5.7以下的版本了
https://flywaydb.org/documentation/database/mysql
原理
Flyway 需要在 DB 中先創(chuàng)建一個(gè) metdata 表 (缺省表名為 flyway_schema_history), 在該表中保存著每次遷移的記錄, 記錄包含遷移腳本的版本號(hào)和 SQL 腳本的 checksum 值. 當(dāng)一個(gè)新的 SQL 腳本被掃描到后, Flyway 解析該 SQL 腳本的版本號(hào), 并和 metadata 表已執(zhí)行的遷移對(duì)比, 如果該 SQL 腳本版本更新的話, 將在指定的 DB 上執(zhí)行該 SQL 文件, 否則跳過該 SQL 文件.
兩個(gè) flyway 版本號(hào)的比較, 采用左對(duì)齊原則, 缺位用 0 代替. 舉例如下:
- 1.2.9.4 比 1.2.9 版本高.
- 1.2.10 比 1.2.9.4 版本高.
- 1.2.10 和 1.2.010 版本號(hào)一樣高, 每個(gè)版本號(hào)部分的前導(dǎo) 0 會(huì)被忽略.
Flyway SQL 文件可以分為兩類:
- Versioned :用于版本升級(jí), 每個(gè)版本有唯一的版本號(hào)并只能 apply 一次
- Repeatable :指可重復(fù)加載的 migration, 一旦 SQL 腳本的 checksum 有變動(dòng), flyway 就會(huì)重新應(yīng)用該腳本. 它并不用于版本更新, 這類的 migration 總是在 versioned migration 執(zhí)行之后才被執(zhí)行
默認(rèn)情況下, Migration SQL的命名規(guī)則如下圖:
img
其中的文件名由以下部分組成,除了使用默認(rèn)配置外,某些部分還可自定義規(guī)則.
- prefix: 可配置,前綴標(biāo)識(shí),默認(rèn)值 V 表示 Versioned, R 表示 Repeatable
- version: 標(biāo)識(shí)版本號(hào), 由一個(gè)或多個(gè)數(shù)字構(gòu)成, 數(shù)字之間的分隔符可用點(diǎn).或下劃線_
- separator: 可配置, 用于分隔版本標(biāo)識(shí)與描述信息, 默認(rèn)為兩個(gè)下劃線__
- description: 描述信息, 文字之間可以用下劃線或空格分隔
- suffix: 可配置, 后續(xù)標(biāo)識(shí), 默認(rèn)為.sql*
Flyway 的 metadata 表結(jié)果如下:
- 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;
高級(jí)
基于Java的遷移回調(diào)
Flyway使我們能夠使用兩種不同的方法(Java或SQL)創(chuàng)建回調(diào)。前者是最靈活的一種。它為我們提供了執(zhí)行任意代碼的自由。
核心代碼如下:
- import lombok.extern.slf4j.Slf4j;
- import org.flywaydb.core.api.callback.BaseCallback;
- import org.flywaydb.core.api.callback.Context;
- import org.flywaydb.core.api.callback.Event;
- import org.flywaydb.core.internal.jdbc.JdbcTemplate;
- import org.springframework.context.annotation.Configuration;
- import java.sql.SQLException;
- @Configuration
- @Slf4j
- public class ExampleFlywayCallback extends BaseCallback {
- @Override
- public void handle(Event event, Context context) {
- switch (event) {
- // 在每次成功遷移后觸發(fā)。此事件將在與遷移相同的事務(wù)中觸發(fā)
- case AFTER_EACH_MIGRATE:
- log.info("{},", event);
- final JdbcTemplate jdbcTemplate = new JdbcTemplate(
- context.getConnection());
- // Create 10 random users
- for (int i = 1; i <= 10; i++) {
- try {
- jdbcTemplate.execute(String.format("insert into test_user"
- + " (username, first_name, last_name) values"
- + " ('%d@reflectoring.io', 'Elvis_%d', 'Presley_%d')", i, i, i));
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- }
- }
- }
- }
- }
我們可以在Java遷移回調(diào)中執(zhí)行所需的任何邏輯,可以靈活地實(shí)現(xiàn)更多變態(tài)需求。
參考:
https://www.cnblogs.com/harrychinese/p/springboot_flyway.html
https://blog.csdn.net/qq_38455201/article/details/103493041