boot-admin整合Liquibase實現資料庫版本管理

2023-05-05 21:00:50

Liquibase 和 Flyway 是兩款成熟的、優秀的、開源/商業版的資料庫版本管理工具,鑑於 Flyway 的社群版本對 Oracle 資料庫支援存在限制,所以 boot-admin 選擇整合 Liquibase 提供資料庫版本管理能力支援。
Liquibase 開源版使用 Apache 2.0 協定。

Liquibase的適用情形?

  • 在你的專案進行版本升級的時候,大概率情況下資料庫也需要同步升級,Liquibase 會自動掃描資料庫遷移檔案(changeSet),將遷移檔案的版本號與歷史記錄表(changelog )中的版本號進行對比,略過已執行的的遷移檔案,順序執行未執行的新版本遷移檔案,最終實現資料庫與程式碼版本相匹配;
  • 當多人共同作業開發專案的時候,系統原始碼可使用 git 保持同步,那麼資料庫的同步就可交由 liquibase 來保證;
  • 使用 liquibase 可以方便地比較兩個資料庫的差異;
  • 使用 liquibase 還支援資料庫版本回滾。

Liquibase的優點有哪些?

  1. 組態檔支援SQL、XML、JSON 或者 YAML;
  2. 可相容14種主流資料庫如 oracle,mysql 等,支援平滑遷移;
  3. 版本控制按序執行;
  4. 可以用上下文控制sql在何時何地如何執行;
  5. 具備在應用中具有if / then邏輯的能力;
  6. 支援 schema 的變更;
  7. 根據組態檔自動生成sql語句用於預覽;
  8. 可重複執行遷移;
  9. 可外掛拓展;
  10. 可回滾;
  11. 支援schema方式的多租戶(multi-tenant);
  12. 能夠在多種資料庫型別上具有相同的更改描述;
  13. 生成的資料庫歷史記錄檔案;
  14. 能夠輕鬆指定更復雜的多語句更改。

整合要點

boot-admin 是一款採用前後端分離模式、基於 SpringCloud 微服務架構的SaaS後臺管理框架。系統內建基礎管理、許可權管理、執行管理、定義管理、程式碼生成器和辦公管理6個功能模組,整合分散式事務 Seata、工作流引擎 Flowable、業務規則引擎 Drools、後臺作業排程框架 Quartz 等,技術棧包括 Mybatis-plus、Redis、Nacos、Seata、Flowable、Drools、Quartz、SpringCloud、Springboot Admin Gateway、Liquibase、jwt、Openfeign、I18n等。

專案原始碼倉庫github
專案原始碼倉庫gitee

引入Maven依賴

<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-core</artifactId>
</dependency>

新增設定

spring:
  liquibase:
    enabled: true
    change-log: classpath:liquibase/master.xml

建立master.xml

在 resources 下建立資料夾 liquibase ,建立檔案 master.xml

<databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
         http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">

    <includeAll path="liquibase/changelogs/" relativeToChangelogFile="false"/>

</databaseChangeLog>

在 liquibase 資料夾下建立 changelogs 和 sql 兩個資料夾,如下圖所示:

編寫資料庫變更單元 changeSet

在 resources\liquibase\changelogs 下建立 changeSet 檔案,推薦每月一個 xml 檔案,檔名格式:【changelog-年度+月份.xml】,如:changelog-202304.xml
常用操作舉例:

建立表

    <changeSet author="admin (generated)" id="00001-9">
        <createTable remarks="行政區劃表" tableName="TB_ADM_DIV">
            <column name="GUID" remarks="主鍵" type="NVARCHAR2(38)">
                <constraints nullable="false" primaryKey="true" primaryKeyName="PK_TB_ADM_DIV"/>
            </column>
            <column name="ADM_DIV_CODE" remarks="行政區劃程式碼" type="NVARCHAR2(12)">
                <constraints nullable="false"/>
            </column>
            <column name="ADM_DIV_NAME" remarks="行政區劃名稱" type="NVARCHAR2(100)">
                <constraints nullable="false"/>
            </column>
            <column name="CREATE_BY" remarks="記錄建立者" type="NVARCHAR2(100)">
                <constraints nullable="false"/>
            </column>
            <column name="CREATE_TIME" remarks="記錄建立時間" type="${type.datetime}">
                <constraints nullable="false"/>
            </column>
            <column name="MODIFY_BY" remarks="記錄最後修改者" type="NVARCHAR2(100)">
                <constraints nullable="false"/>
            </column>
            <column name="MODIFY_TIME" remarks="記錄最後修改時間" type="${type.datetime}">
                <constraints nullable="false"/>
            </column>
            <column defaultValueComputed="${now}" name="DATESTAMP" remarks="時間戳" type="${type.datetime}">
                <constraints nullable="false"/>
            </column>
            <column name="ENABLED" remarks="啟用狀態;ENABLED" type="NVARCHAR2(1)">
                <constraints nullable="false"/>
            </column>
            <column name="DELETED" remarks="刪除狀態;DELETED" type="NVARCHAR2(1)">
                <constraints nullable="false"/>
            </column>
            <column name="VERSION" remarks="樂觀鎖" type="${type.int}">
                <constraints nullable="false"/>
            </column>
            <column name="REMARKS" remarks="備註" type="NVARCHAR2(900)"/>
            <column name="TENANT_ID_" remarks="租戶ID" type="NVARCHAR2(38)">
                <constraints nullable="false"/>
            </column>
            <column name="PARENT_GUID" remarks="父級GUID" type="NVARCHAR2(38)">
                <constraints nullable="false"/>
            </column>
            <column name="LEAF" remarks="是否末級;YESNO" type="NVARCHAR2(1)">
                <constraints nullable="false"/>
            </column>
            <column name="SORT" remarks="順序號" type="${type.int}">
                <constraints nullable="false"/>
            </column>
        </createTable>
    </changeSet>

新增表欄位

<changeSet author="admin" id="00002-1">
    <addColumn tableName="TB_ADM_DIV">
       <column name="EXT" remarks="擴充套件" type="VARCHAR(64)"/>
    </addColumn>
</changeSet>

刪除表欄位

    <changeSet author="admin" id="00002-2">
        <dropColumn tableName="TB_ADM_DIV" columnName="EXT"/>
    </changeSet>

修改表欄位說明

    <changeSet author="admin" id="00002-3">
        <setColumnRemarks tableName="TB_ADM_DIV" columnName="EXT" remarks="擴充套件欄位"/>
    </changeSet>

修改表欄位型別

    <changeSet author="admin" id="00002-4">
        <modifyDataType tableName="TB_ADM_DIV" columnName="EXT" newDataType="VARCHAR2(2000)"/>
    </changeSet>

建立檢視

    <changeSet author="admin (generated)" id="00001-1" dbms="oracle">
        <createView fullDefinition="true" remarks="表和檢視" viewName="V_TABLES_MASTER">
            CREATE OR REPLACE FORCE VIEW V_TABLES_MASTER (TABLE_SCHEMA, TABLENAME, TABLETYPE, COMMENTS, TENANT_ID_) AS
            select SYS_CONTEXT('USERENV','CURRENT_SCHEMA') TABLE_SCHEMA,
            t.tname tableName,
            tabtype tabletype,
            f.comments comments,
            'DEMO' TENANT_ID_
            from tab t
            inner join user_tab_comments f
            on t.tname = f.table_name
            where tname != 'DATABASECHANGELOG'
            and tname != 'DATABASECHANGELOGLOCK'
            and tname != 'UNDO_LOG'
        </createView>
    </changeSet>
    <changeSet author="37514 (generated)" id="00000-2" dbms="mysql">
        <createView fullDefinition="true" remarks="表和檢視" viewName="V_TABLES_MASTER">
            CREATE OR REPLACE VIEW V_TABLES_MASTER  AS
            SELECT
            TABLE_SCHEMA,
            TABLE_NAME AS TABLENAME,
            case when table_type='BASE TABLE' then 'TABLE' ELSE table_type END AS TABLETYPE,
            TABLE_COMMENT AS COMMENTS,
            'DEMO' TENANT_ID_
            FROM
            information_schema.`TABLES`
            WHERE table_name != 'databasechangeloglock' AND TABLE_NAME != 'databasechangelog' AND TABLE_NAME != 'undo_log'
        </createView>
    </changeSet>

相容 Oracle 和 Mysql 設定

    <property name="type.datetime" value="date" dbms="oracle"/>
    <property name="type.datetime" value="timestamp" dbms="mysql"/>
    <property name="type.int" value="NUMBER(*, 0)" dbms="oracle"/>
    <property name="type.int" value="INT" dbms="mysql"/>
    <property name="type.decimal" value="NUMBER(*, 2)" dbms="oracle"/>
    <property name="type.decimal" value="DECIMAL" dbms="mysql"/>
    <property name="now" value="SYSDATE" dbms="oracle"/>
    <property name="now" value="now()" dbms="mysql,h2"/>
    <property name="autoIncrement" value="true" dbms="mysql,h2,postgresql,oracle"/>
    <property name="amount" value="decimal(20,2)"/>
    <property name="uuid" value="sys_guid()" dbms="oracle"/>
    <property name="uuid" value="UUID()" dbms="mysql"/>

執行 SQL 檔案

    <changeSet id="20000820-003" author="Administrator" dbms="oracle">
        <sqlFile dbms="oracle" path="classpath:/liquibase/sql/seata-undo_log-oracle.sql" />
    </changeSet>
    <changeSet id="20000820-003" author="Administrator" dbms="mysql">
        <sqlFile dbms="mysql" path="classpath:/liquibase/sql/seata-undo_log-mysql.sql" />
    </changeSet>

需將對應 sql 檔案放在指定資料夾中。

Liquibase changeSet常用命令清單

add

標籤 描述
addAutoIncrement 將一個已存在的列轉換為自增
addColunm 增加列
addDefaultValue 對已存在的列增加預設值
addForeignKeyConstraint 對已存在的列增加外來鍵約束
addLookupTable 建立外來鍵關聯的表
addNotNullConstraint 對已存在的列增加非空約束
addPrimaryKey 對已存在的列增加主鍵約束
ddUniqueConstraint 對已存在的列增加主鍵約束

create

標籤 描述
createIndex 建立索引
createProcedure 建立儲存過程
createSequence 建立序列
createTable 建立表
createView 建立檢視

drop

標籤 描述
dropAllForeignKeyConstraints 刪除全部的外來鍵約束
dropColumn 刪除列
dropDefaultValue 刪除預設值設定
dropForeignKeyConstraint 刪除某一列的外來鍵約束
dropNotNullConstraint 刪除非空約束
dropIndex 刪除索引
dropSequence 刪除約束
dropProcedure 刪除儲存過程
dropPrimaryKey 刪除主鍵
dropTable 刪除表
dropUniqueConstraint 刪除唯一性約束
dropView 刪除檢視

rename

標籤 描述
renameColumn 重新命名列
renameSequence 重新命名序列
renameTable 重新命名錶
renameView 重新命名檢視

sql

標籤 描述
sql 原生SQL
sqlFile 引入 SQL 檔案

other

標籤 描述 標籤 描述
alterSequence 修改序列 customChange 自定義change型別,需要自己實現liquibase.change.custom.CustomSqlChange、liquibase.change.custom.CustomTaskChange介面
delete 刪除資料 empty 空操作
executeCommand 執行系統命令,如 mysqldump insert 插入資料
loadData 載入 csv 檔案到已存在的表中 loadUpdateData 載入 csv 檔案到已存在的表中,但是會判斷是否存在,存在更新,否則新增
mergeColumns 將兩列值合併在一起,存入新列中 modifyDataType 修改列資料型別
output 記錄一條訊息並繼續執行 setColumnRemarks 列上新增備註
setTableRemarks 表上新增備註 stop 通過訊息停止 Liquibase
tagDatabase 將標籤應用於資料庫以供將來回滾 update 更新資料