1. 程式人生 > >Liquibase-數據庫版本管理使用

Liquibase-數據庫版本管理使用

所有 cep back sets --help 書寫 ever connector 性問題

  • Liquibase-數據庫版本管理
    • 一、數據庫版本管理說明
      • 1、liquibase介紹
        • 1.1、changelog文件格式
      • 2、flyway介紹
      • 3、liquibase與flyway比較
    • 二、spring boot + liquibase
      • 1、gradle配置引入liquibase包:
      • 2、修改application.yml或加LiquibaseConfig.java
        • 2.1、application.yml
        • 2.2、LiquibaseConfig.java
      • 3、新增changelog.xml
        • 3.1、新增master.xml
        • 3.2、新增V1.1__init.sql(以sql語句方式,也可以用xml、yml、json請查看官網)
    • 三、gradle + liquibase插件
      • 1、修改build.gradle文件
        • 1.1、多模塊項目在根路徑修改build.gradle
        • 1.2、子模塊修改build.gradle
      • 2、命令示例
      • 3、命令詳解
        • 3.1、數據庫更新命令
        • 3.2、數據庫回滾命令
          • 3.2.1、直接執行回滾
          • 3.2.2、生成回滾腳本
          • 3.2.3、生成“未來回滾”腳本
          • 3.2.4 回滾命令
        • 3.3、差異命令
        • 3.4、文檔命令
        • 3.5、維護命令
        • 3.6、必需參數
        • 3.7、可選參數
        • 3.8、必需的Diff參數
        • 3.9、可選的Diff參數
        • 3.10、更改日誌屬性
        • 3.11、liquibase.activities詳解
      • 4、插件升級

Liquibase-數據庫版本管理

一、數據庫版本管理說明

數據庫遷移工具很多,這裏我們選擇Flyway和Liquibase來說主要是兩個原因,
一是它們都是Java生態圈的,其次就是Spring Boot提供了這兩者的內建支持,可以很快應用到產品中。

1、liquibase介紹

LiquiBase是一個用於數據庫重構和遷移的開源工具,通過日誌文件的形式記錄數據庫的變更,然後執行日誌文件中的修改,將數據庫更新或回滾到一致的狀態。  
LiquiBase的主要特點有:
支持幾乎所有主流的數據庫,如MySQL, PostgreSQL, Oracle, Sql Server, DB2支持多開發者的協作維護  
日誌文件支持多種格式,如XML, YAML, JSON, SQL支持多種運行方式,如命令行、Spring集成、Maven插件、Gradle插件等  

1.1、changelog文件格式

changelog是LiquiBase用來記錄數據庫的變更,一般放在CLASSPATH下,然後配置到執行路徑中。  
changelog支持多種格式,主要有XML/JSON/YAML/SQL,其中XML/JSON/YAML除了具體格式語法不同,節點配置很類似,SQL格式中主要記錄SQL語句,以下示例僅給出SQL格式的示例,更多的格式示例請參考文檔

2、flyway介紹

flyway相對簡單,直接將你需要執行的SQL語句保存為文件,放入應用中執行即可。
Flyway的好處在於簡單,而且直接書寫SQL並不需要額外的學習。社區版的不支持UNDO操作,需要購買企業版。

3、liquibase與flyway比較

Flyway 自動升級(自動發現更新項):Flyway 會將任意版本的數據庫升級到最新版本。
Flyway 可以脫離JVM 環境通過命令行執行,可以通過Ant 腳本執行,通過Maven 腳本執行(這樣就可以在集成環境自動執行),並且可以在應用中執行(比如在應用啟動時執行)。
Flyway 規約優於配置:Flyway 有一套默認的規約,所以不需要修改任何配置就可以正常使用。
Flyway 既支持SQL 腳本,又支持Java 代碼:可以使用SQL 腳本執行數據庫更新,也可以使用Java 代碼來進行一些高級數據升級操作。
Flyway 高可靠性:在集群環境下進行數據庫升級是安全可靠的。
Flyway 支持清除已存在的庫表結構:Flyway 可以清除已存在的庫表結構,可以從零開始搭建您的庫表結構,並管理您的數據庫版本升級工作
Flyway 支持失敗修復。新的2.0 版本提供了repair 功能,用於解決數據庫更新操作失敗問題。

Liquibase 自動升級,將任意版本的數據庫升級到最新版本。
Liquibase 可以根據數據庫的情況為你生成最後的遷移語句,同時因為數據庫變動首先是被Liquibase解析,所以也可以簡單支持回滾。
Liquibase 支持大部分常見的數據庫變動操作,比如建表,刪表,變動字段等等
Liquibase 可以在不使用SQL的情況下造成數據庫變動,其可讀性更高一些,特別是團隊並不直接使用SQL而整體相關知識儲備不完善的情況下優勢更明顯。
兩款數據庫遷移工具其實定位上是差別的。一般小項目整體變動不大的用Flyway,大應用和企業應用用Liquibase更合適。

二、spring boot + liquibase

註:spring boot + liquibase此方式僅僅是簡單的實現更新數據庫表結構,用於啟動項目時更新表結構。

1、gradle配置引入liquibase包:

dependencies {
    compile group: ‘org.liquibase‘, name: ‘liquibase-core‘, version: ‘3.5.3‘
    testCompile group: ‘junit‘, name: ‘junit‘, version: ‘4.12‘
}

2、修改application.yml或加LiquibaseConfig.java

2.1、application.yml

liquibase:
  change-log: classpath:/db/changelog/master.xml
  user: root
  password: 1qaz2wsx
  url: jdbc:mysql://127.0.0.1:3306/test_1.0.1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullNamePatternMatchesAll=true&useSSL=true
  drop-first: false

2.2、LiquibaseConfig.java

@Configuration
public class LiquibaseConfig {
    @Bean
    public SpringLiquibase liquibase(DataSource dataSource) {
        SpringLiquibase liquibase = new SpringLiquibase();
        liquibase.setDataSource(dataSource);
        liquibase.setChangeLog("classpath:/db/changelog/master.xml");
        liquibase.setContexts("development,test,production");
        liquibase.setShouldRun(true);
        return liquibase;
    }
}

3、新增changelog.xml

3.1、新增master.xml

在src/main.resouces下新增db/changelog/master.xml。
master.xml內容如下:

<?xml version="1.0" encoding="utf-8"?>
<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.5.xsd">
    <include file="classpath:/db/changelog/V1.1__init.sql" relativeToChangelogFile="false"/>
</databaseChangeLog>

3.2、新增V1.1__init.sql(以sql語句方式,也可以用xml、yml、json請查看官網)

在src/main.resouces/db/changelog下新增db/changelog/V1.1__init.sql。
V1.1__init.sql內容如下:

--liquibase formatted sql
--changeset whx:1.1
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for test_user_tab
-- ----------------------------
DROP TABLE IF EXISTS `test_user_tab`;
CREATE TABLE `test_user_tab` (
  `userId` int(11) NOT NULL AUTO_INCREMENT,
  `userAccount` varchar(16) NOT NULL,
  `password` varchar(32) NOT NULL,
  `userStatus` tinyint(1) NOT NULL DEFAULT ‘1‘,
  `addTime` datetime NOT NULL,
  PRIMARY KEY (`userId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=測試用戶表‘;

--changeset whx:1.2
ALTER TABLE `test_user_tab`
DROP COLUMN `addTime`;
--rollback ALTER TABLE `test_user_tab` ADD COLUMN `addTime`  datetime NOT NULL AFTER `userStatus`;

--changeset whx:1.3

ALTER TABLE `test_user_tab`
ADD COLUMN `addTime`  datetime NOT NULL AFTER `userStatus`;
--rollback ALTER TABLE `test_user_tab` DROP COLUMN `addTime`;

--changeset whx:1.4
ALTER TABLE `test_user_tab`
DROP COLUMN `addTime`;
--rollback ALTER TABLE `test_user_tab` ADD COLUMN `addTime`  datetime NOT NULL AFTER `userStatus`;

--changeset whx:1.5
ALTER TABLE `test_user_tab`
ADD COLUMN `addTime`  datetime NOT NULL AFTER `userStatus`;
--rollback ALTER TABLE `test_user_tab` DROP COLUMN `addTime`;

啟動項目可以查看數據庫此時新增了三張表:

databasechangelog
databasechangeloglock
test_user_tab

三、gradle + liquibase插件

plugin地址:https://github.com/liquibase/liquibase-gradle-plugin

1、修改build.gradle文件

1.1、多模塊項目在根路徑修改build.gradle

註:此方式將使所有model都有liquibase插件,在執行命令可能因為文件重復導致失敗,不建議此方式。

group = ‘test‘
version = ‘0.0.1-SNAPSHOT‘

buildscript {
    ext {
    repositories {
        mavenCentral()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath "gradle.plugin.org.liquibase:liquibase-gradle-plugin:2.0.1"
    }
}

subprojects {

    apply plugin: ‘java‘
    apply plugin: ‘eclipse‘
    apply plugin: "org.liquibase.gradle"
    sourceCompatibility = 1.8

    repositories {
        mavenCentral()
        maven {
            url ‘http://maven.aliyun.com/nexus/content/groups/public/‘
        }
    }

    dependencies {
        liquibaseRuntime ‘org.liquibase:liquibase-core:3.5.3‘
        liquibaseRuntime ‘org.liquibase:liquibase-groovy-dsl:2.0.1‘
        liquibaseRuntime ‘mysql:mysql-connector-java:5.1.34‘
    }

    liquibase {
        activities {
            main {
                changeLogFile "${this.rootDir}/user/src/main/resources/db/changelog/V1.1__init.sql"
                url "jdbc:mysql://127.0.0.1:3306/test_1.0.1?useUnicode=true&characterEncoding=UTF-8"
                username "root"
                password "1qaz2wsx"
            }
            runList = ‘main‘
        }
    }
}

1.2、子模塊修改build.gradle

例如:core model的core.gradle文件,推薦此方式。

group ‘projectManage‘
version ‘1.0-SNAPSHOT‘

apply plugin: ‘java‘
sourceCompatibility = 1.8

buildscript {
    repositories {
        mavenCentral()
        maven { url "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath "org.liquibase:liquibase-gradle-plugin:2.0.1"
    }
}
apply plugin: ‘org.liquibase.gradle‘

dependencies {

    liquibaseRuntime ‘org.liquibase:liquibase-core:3.5.3‘
    liquibaseRuntime ‘org.liquibase:liquibase-groovy-dsl:2.0.1‘
    liquibaseRuntime ‘mysql:mysql-connector-java:5.1.34‘

    compile project(":common")
    testCompile group: ‘junit‘, name: ‘junit‘, version: ‘4.12‘

    liquibase {
        activities {
            main {
                changeLogFile "${this.rootDir}/core/src/main/resources/db/changelog/V1.1__init.sql"
                //changeLogFile "${this.rootDir}/core/src/main/resources/db/changelog/changelog.mysql.sql"
                url "jdbc:mysql://127.0.0.1:3306/yb_oa_xmgl_1.0.1?useUnicode=true&characterEncoding=UTF-8"
                username "root"
                password "1qaz2wsx"
            }
            runList = ‘main‘
        }
    }
}

說明:
0、註意mysql驅動版本
??liquibaseRuntime ‘mysql:mysql-connector-java:5.1.34‘
1、註意${this.rootDir}
??changeLogFile "${this.rootDir}/user/src/main/resources/db/changelog/V1.1__init.sql"
??如果不加${this.rootDir}可能會報Gradle Liquibase change log file could not be found
另一種寫法:

liquibase {
   activities {
   main {      
      changeLogFile ‘src/main/resources/db/dbchangelog-master.xml‘
      url ‘jdbc:mysql://localhost:3306/test‘
      username ‘XXX‘
      password ‘XXX‘
      classpath "$rootDir"
     } 
  }
 runList = ‘main‘
}

2、命令示例

0、插件命令 gradle command -PliquibaseCommandValue=<value> # -PliquibaseCommandValue=<value> 為非填。
1、gradle update -PrunList=main  #執行命令,將按V1.1__init.sql中的sql語句更新數據庫。
2、gradle generateChangeLog #數據庫sql文件的標準輸出,執行於已存在表結構的數據庫將會得到表數據結構文件。
註:changeLogFile ‘src/main/resources/db/changelog.mysql.sql‘ ,changelog.xxx.sql允許不存在,執行時將自動創建。xxx代表的是數據庫。  
例如:changelog.h2.sql,必須是此格式,否則將報錯。
3、gradle rollbackCount -PliquibaseCommandValue=1 # rollbackCount 回滾最後的<value>更改集
4、gradle dbDoc # 將在/項目路徑/.idea/dataSources下生成/xxx.xml文件,該文件是對數據庫表數據結構的描述。

3、命令詳解

liquibase官網:https://www.liquibase.org/documentation/command_line.html
註:插件命令 gradle command -PliquibaseCommandValue=<value>
以下操作均已/core/src/main/resources/db/changelog/V1.1__init.sql中的V1.1__init.sql為例子。

3.1、數據庫更新命令

命令描述
update 更新數據庫到當前版本。
updateCount <value> 更新數據庫到指定的value版本,即第幾個changeset。
例如:gradle updateCount -PliquibaseCommandValue=1
將只會執行V1.1__init.sql中--changeset whx:1.1,後續的changeset將不會執行。
若繼續執行value=5,則--changeset whx:1.1~1.5都將執行,且之前的操作並不會沖突。
updateSQL 預執行sql(執行全部changeset),並不會更新數據庫,僅在控制臺輸出。
updateCountSQL <value> 預執行sql到指定的value版本。

3.2、數據庫回滾命令

Liquibase有三種管理回滾的模式:

3.2.1、直接執行回滾

可以直接針對目標數據庫執行回滾命令。如果無法回滾任何更改,您將收到通知,並且不會回滾任何更改。

3.2.2、生成回滾腳本

可以生成回滾數據庫所需的SQL,而不是實際更新數據庫。如果要預覽在實際運行之前將執行的回滾命令,這將非常有用。

3.2.3、生成“未來回滾”腳本

此模式旨在允許在生成遷移腳本的同時生成回滾腳本。它允許獲取更新的應用程序並生成SQL以將數據庫更新為新版本以及SQL,以便在需要時將該新版本恢復到當前版本。當DBA想要控制進入數據庫的SQL時,以及需要內部和/或“SOX兼容”進程的回滾文檔的應用程序時,此功能非常有用。無需在此模式下指定回滾日期,標記或計數。

3.2.4 回滾命令
命令描述
rollback <tag> 要回滾到那個tag。例如:gradle rollback -PliquibaseCommandValue=tag20190107。
需要註意的是在V1.1__init.sql中,必須有--rollback。
例如:
--changeset whx:1.5
ALTER TABLE `test_user_tab`
ADD COLUMN `addTime` datetime NOT NULL AFTER `userStatus`;
--rollback ALTER TABLE `test_user_tab` DROP COLUMN `addTime`;
初始版本的sql數據表結構可以沒有--rollback,但是後續的--changeset建議都加上--rollback。
rollbackToDate <date/time> 設置回滾的日期。日期格式要符合插件執行theDateFormat.getDateInstance()操作設置的日期格式。
rollbackCount <value> value指定往前回滾幾個版本,例如:gradle rollbackCount -PliquibaseCommandValue=1
將會回滾--changeset whx:1.5的操作。
rollbackSQL <tag> 根據tag,預執行rollback。並不會更新數據庫,僅在控制臺輸出。
rollbackToDateSQL <date/time> 根據date/time,預執行rollback。
rollbackCountSQL <value> 根據value,預執行rollback。
futureRollbackSQL SQL以在應用更改日誌中的更改後將數據庫回滾到當前狀態。
updateTestingRollback 更新數據庫,然後在更新之前回滾更改。
generateChangeLog 數據庫sql文件的標準輸出,執行於已存在表結構的數據庫將會得到表數據結構文件。
註:changeLogFile ‘src/main/resources/db/changelog.mysql.sql‘,
changelog.xxx.sql允許不存在,執行時將自動創建。xxx代表的是那種數據庫。
例如:changelog.h2.sql,必須是此格式,否則將報錯。

3.3、差異命令

diff命令用於比較數據庫之間的異同。
註:它目前不檢查:非外鍵約束(檢查等)、存儲過程、數據類型長度。
詳見 3.11、liquibase.activities詳解。

命令描述
diff [diff parameters] 將差異描述寫入標準輸出。
例如:gradle diff -PrunList=diffMain。
diffChangeLog [diff parameters] 寫入更改日誌XML以將基礎數據庫更新到目標數據庫以標準輸出,默認控制臺輸出。
例如:gradle diffChangeLog -PrunList=diffMain。
配置changeLogFile 則按規則輸出。

3.4、文檔命令

命令描述
dbDoc <outputDirectory> 默認將在/項目路徑/.idea/dataSources下生成/xxx.xml文件,該文件是對數據庫表數據結構的描述。
outputDirectory指定輸出路徑,不同後綴文件名將生產不同格式的Doc。
例如 gradle dbDoc -PliquibaseCommandValue=
D:\work_idea\yboa\pro_manage_dev\user\src\main\resources\db\changelog\123.sql
將生成html文件。

3.5、維護命令

命令描述
tag <tag> "標記"當前數據庫狀態以供將來回滾。
例如:gradle tag -PliquibaseCommandValue=tag20190107
tagExists <tag> 檢查給定標記是否已存在。
status
validate 檢查更改日誌中的錯誤。
changelogSync 將所有更改標記為在數據庫中執行。
changelogSyncSQL SQL以將在數據庫中執行的所有更改標記為STDOUT。
markNextChangeSetRan 將下一個更改集標記為在數據庫中執行。
listLocks 列出當前鎖定數據庫更改日誌的人員。
releaseLocks 釋放數據庫更改日誌上的所有鎖定。
dropAll 刪除用戶擁有的所有數據庫對象。請註意,不刪除函數,過程和包(1.8.1中的限制)。
clearCheckSums 從數據庫中刪除當前的校驗和。在下次運行時,將重新計算校驗和。

3.6、必需參數

詳見:build.gradle文件中的配置

命令描述
--changeLogFile=<path and filename> 要使用的changelog文件。
--username=<value> 數據庫用戶名
--password=<value> 數據庫密碼。
--url=<value> 數據庫JDBC URL。
--driver=<jdbc.driver.ClassName> 數據庫驅動程序類名。

3.7、可選參數

命令描述
--classpath=<value> 包含遷移文件和JDBC驅動程序的類路徑。
--contexts=<value> ChangeSet上下文要執行。
--defaultSchemaName=<schema> 指定用於托管數據庫對象和Liquibase控制表的默認架構。
--databaseClass=<custom.DatabaseImpl> 指定要使用的自定義數據庫實現
--defaultsFile=</path/to/file> 包含默認選項值的文件。(默認值:./ liquibase.properties)
--includeSystemClasspath=<true or false> 在Liquibase類路徑中包含系統類路徑。(默認值:true)
--promptForNonLocalDatabase=<true or false> 提示非本地主機數據庫。(默認值:false)
--currentDateTimeFunction=<value> 覆蓋SQL中使用的當前日期時間函數。適用於不受支持的數據庫。
--logLevel=<level> 執行日誌級別((debug, info, warning, severe, off)。
--help 輸出命令行參數幫助。
--exportDataDir 將保留insert語句csv文件的目錄(generateChangeLog命令所需)。
--propertyProviderClass=<properties.ClassName> 要使用的自定義Properties實現

3.8、必需的Diff參數

命令描述
--referenceUsername=<value> 基礎數據庫用戶名
--referencePassword=<value> 基礎數據庫密碼。
--referenceUrl=<value> 基礎數據庫URL。

3.9、可選的Diff參數

命令描述
--referenceDriver=<jdbc.driver.ClassName> 基礎數據庫驅動程序類名。

3.10、更改日誌屬性

命令描述
-D<property.name>=<property.value> 傳遞名稱/值對以替換更改日誌中的$ {}塊。

3.11、liquibase.activities詳解

liquibase {
    activities {
        main {
            changeLogFile "${this.rootDir}/core/src/main/resources/db/changelog/V1.1__init.sql"
            //changeLogFile "${this.rootDir}/core/src/main/resources/db/changelog/changelog.mysql.sql"
            url "jdbc:mysql://127.0.0.1:3306/yb_oa_xmgl_1.0.1?useUnicode=true&characterEncoding=UTF-8"
            username "root"
            password "1qaz2wsx"
            //driver "" // 該參數可非必填,url將自動匹配驅動。
            //exportDataDir // 將保留insert語句csv文件的目錄(generateChangeLog命令所需)。
            
        }
        security {
            changeLogFile ‘src/main/db/security.groovy‘
            url project.ext.securityUrl
            username project.ext.securityUsername
            password project.ext.securityPassword
        }
        /**比較數據庫之間的差異**/
        diffMain {
            //若不配置changeLogFile 則將在控制臺進行xml輸出。diff.mysql.sql會自動創建,必須以 *.databaseType.sql才會生成sql文件
            changeLogFile "${this.rootDir}/core/src/main/resources/db/changelog/diff.mysql.sql"
            url "jdbc:mysql://127.0.0.1:3306/yb_oa_xmgl_1.0.1?useUnicode=true&characterEncoding=UTF-8"
            username "root"
            password ‘1qaz2wsx‘
            referenceUrl "jdbc:mysql://127.0.0.1:3306/yb_oa_xmgl_1.0.2?useUnicode=true&characterEncoding=UTF-8"
            referenceUsername "root"
            referencePassword ‘1qaz2wsx‘
        }
        runList = ‘main‘ # 不同環境可執行不同的main方法, 例如:runList = ‘diffMain‘
    }
}

4、插件升級

升級Liquibase Gradle插件本身的版本

大多數時候,Liquibase的新版本與舊版本的版本相同,但有時新版本與現有的更改集存在兼容性問題,就像Liquibase 3發布時一樣。  
發生這種情況時,建議執行以下升級程序:
1、確保所有Liquibase的管理數據庫是最新通過運行 gradle update它們升級到Liquibase插件的新版本之前。

2、創建一個新的丟棄數據庫來測試Liquibase更改集。gradle update使用最新版本的Liquibase插件在新數據庫上運行 這很重要,因為Groovy DSL中的項目已棄用,並且因為不同Liquibase版本生成SQL的方式存在一些細微差別。 
例如,使用defaultValue: "0"Liquibase 2中的工作正常,在MySql中向布爾列添加默認值,但在Liquibase 3中,  
它生成的SQL不適用於MySql - defaultValueNumeric: 0需要使用它。

3、一旦確定所有更改集都使用最新的Liquibase插件,請清除所有由Liquibase 2舊版本計算的校驗和,方法是gradle clearChecksums對所有數據庫運行。

4、最後,gradle changeLogSync在所有數據庫上運行以計算新的校驗和。

Liquibase-數據庫版本管理使用