Flyway版本化管理資料庫指令碼

李福春發表於2020-08-30

假如我們有一個叫shiny的專案,它是由一個程式Shiny-Server 和一個資料庫 Shiny-DB組成的;

簡單結構圖如下:

image.png

但是很多時候,現實開發團隊是這樣的:

image.png

我們的專案shiny專案的執行環境是有多套的,

我們擅長解決程式碼層面的問題。

版本控制工具git非常普遍而且好用

我們有持續整合和持續構建的工具

我們很好的定義了測試和生產環境的釋出流程

image.png

但是我們的資料庫的版本如何控制呢?

image.png

當前現狀

非常不幸的是我們還不能很好的處理資料庫的版本管理問題,

很多的專案依賴運維人員手動的執行SQL指令碼,

有的時候甚至為了快速解決bug去快速的在命令列上執行SQL指令碼,那麼問題來了。

通常這些問題的答案是:鬼知道。

引入目的

flyway解決了上面的這些問題。

目前Flyway支援的資料庫還是挺多的,包括:

Oracle, SQL Server, SQL Azure, DB2, DB2 z/OS,

MySQL(including Amazon RDS), MariaDB,

Google Cloud SQL, PostgreSQL(including Amazon RDS and Heroku),

Redshift, Vertica, H2, Hsql, Derby, SQLite, SAP HANA,

solidDB, Sybase ASE and Phoenix。

Flyway的執行流程

Flyway是一款開源的資料庫版本管理工具,

它更傾向於規約優於配置的方式。

Flyway可以獨立於應用實現管理並跟蹤資料庫變更,支援資料庫版本自動升級,

並且有一套預設的規約,不需要複雜的配置,

Migrations可以寫成SQL指令碼,也可以寫在Java程式碼中,

不僅支援Command Line和Java API,還支援Build構建工具和Spring Boot等,

同時在分散式環境下能夠安全可靠地升級資料庫,同時也支援失敗恢復等。

Flyway工作流程.png

每次不管是資料庫的表結構或者表資料的變更,

你只需要把問題當成一次資料庫的升級,

簡單的建立一個比當前版本更高的版本的遷移SQL檔案或者Java檔案,

下次Flyway啟動的時候,他會找到這些指令碼並把它更新到資料庫。

指令碼或者Java遷移指令碼的命名規則:

其中的檔名由以下部分組成,除了使用預設配置外,某些部分還可自定義規則。

  • prefix: 可配置,字首標識,預設值V表示Versioned,R表示Repeatable
  • version: 標識版本號,由一個或多個數字構成,數字之間的分隔符可用點.或下劃線_
  • separator: 可配置,用於分隔版本標識與描述資訊,預設為兩個下劃線__
  • description: 描述資訊,文字之間可以用下劃線或空格分隔
  • suffix: 可配置,後續標識,預設為.sql

實現路徑

真實專案版本更新場景中,我們不可能再基於人力去做這件事情,我們選擇的是API的方式。

使用步驟如下:

API方式使用Flyway.png

一般大家都是寫SQL指令碼,也支援通過寫Java程式碼的方式來實現。

Java方式寫遷移功能

使用步驟:

Java程式碼方式寫遷移程式碼.png

目前的整合方式

使用的是springboot的方式整合了Flyway;

COLA引入Flyway的流程.png

配置引數:可自行翻譯和參考選擇去配置

flyway.baseline-description= # The description to tag an existing schema with when executing baseline.
flyway.baseline-version=1 # Version to start migration.
flyway.baseline-on-migrate=false # Whether to execute migration against a non-empty schema with no metadata table
flyway.check-location=false # Check that migration scripts location exists.
flyway.clean-on-validation-error=false # will clean all objects. Warning! Do NOT enable in production!
flyway.enabled=true # Enable flyway.
flyway.encoding=UTF-8 # The encoding of migrations.
flyway.ignore-failed-future-migration=true # Ignore future migrations when reading the metadata table.
flyway.init-sqls= # SQL statements to execute to initialize a connection immediately after obtaining it.
flyway.locations=classpath:db/migration # locations of migrations scripts.
flyway.out-of-order=false # Allows migrations to be run "out of order".
flyway.placeholder-prefix=  # The prefix of every placeholder.
flyway.placeholder-replacement=true # Whether placeholders should be replaced.
flyway.placeholder-suffix=} # The suffix of every placeholder.
flyway.placeholders.*= # Placeholders to replace in Sql migrations.
flyway.schemas= # Default schema of the connection and updating
flyway.sql-migration-prefix=V # The file name prefix for Sql migrations
flyway.sql-migration-separator=__ # The file name separator for Sql migrations
flyway.sql-migration-suffix=.sql # The file name suffix for Sql migrations
flyway.table=schema_version # The name of Flyway's metadata table.
flyway.url= # JDBC url of the database to migrate. If not set, the primary configured data source is used.
flyway.user= # Login user of the database to migrate. If not set, use spring.datasource.username value.
flyway.password= # JDBC password if you want Flyway to create its own DataSource.
flyway.validate-on-migrate=true # Validate sql migration CRC32 checksum in classpath.
package db.migration;

/**
 * @author carter
 * create_date  2020/8/13 17:39
 * description     java資料庫變更模板程式碼
 */


import lombok.extern.slf4j.Slf4j;
import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;

import java.sql.ResultSet;
import java.sql.Statement;

@Slf4j
public class V2__test extends BaseJavaMigration {
    @Override
    public void migrate(Context context) throws Exception {
        try (Statement select = context.getConnection().createStatement()) {
            try (ResultSet rows = select.executeQuery("SELECT 1")) {
                while (rows.next()) {
                    int id = rows.getInt(1);
                    String anonymizedName = "Anonymous" + id;
                    log.info("執行sql指令碼:{}",anonymizedName);
                }
            }
        }
    }
}


資料來源

官網: https://flywaydb.org/

實戰: https://blog.waterstrong.me/flyway-in-practice/

如有問題,請留言。

原創不易,關注誠可貴,轉發價更高!轉載請註明出處,讓我們互通有無,共同進步,歡迎溝通交流。
我會持續分享Java軟體程式設計知識和程式設計師發展職業之路,歡迎關注,我整理了這些年程式設計學習的各種資源,關注公眾號‘李福春持續輸出’,傳送'學習資料'分享給你!

相關文章