liquibase原理

LiquiBase是一個用於數據庫重構和遷移的開源工具,經過日誌文件的形式記錄數據庫的變動,而後執行日誌文件中的修改,將數據庫更新或回滾到一致的狀態。html

LiquiBase的主要特色有:java

  • 支持幾乎全部主流的數據庫,如MySQL, PostgreSQL, Oracle, Sql Server, DB2等;
  • 支持多開發者的協做維護;
  • 日誌文件支持多種格式,如XML, YAML, JSON, SQL等;
  • 支持多種運行方式,如命令行、Spring集成、Maven插件、Gradle插件等;

本文首先簡單介紹一下LiquiBase的changelog文件的經常使用標籤配置,而後介紹在Maven中集成並運行LiquiBase。mysql

1. changelog文件格式

changelog是LiquiBase用來記錄數據庫的變動,通常放在CLASSPATH下,而後配置到執行路徑中。sql

changelog支持多種格式,主要有XML/JSON/YAML/SQL,其中XML/JSON/YAML除了具體格式語法不一樣,節點配置很相似,SQL格式中主要記錄SQL語句,這裏僅給出XML格式和SQL格式的示例,更多的格式示例請參考文檔
數據庫

changelog.xmlmaven

<changeSet id="2" author="daniel" runOnChange="true">
    <insert tableName="contest_info">
        <column name="id">3</column>
        <column name="title">title 3</column>
        <column name="content">content 3</column>
    </insert>
</changeSet>

changelog.sqlide

--liquibase formatted sql
--changeset daniel:16040707
CREATE TABLE `role_authority_sum` (
  `row_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
  `role_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '關聯role的role_id',
  `authority_sum` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'perms的值的和',
  `data_type_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '關聯data_type的id',
  PRIMARY KEY (`row_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色的權限值的和,如角色有RD權限,則和爲2+8=10';

 

 

 

2. 經常使用的標籤及命令

2.1 標籤

  一個<changeSet>標籤對應一個變動集,由id、name、以及changelog的文件路徑組成惟一標識。changelog在執行的時候並非按照id的順序,而是按照changeSet在changelog中出現的順序。函數

LiquiBase在執行changelog時,會在數據庫中插入兩張表:DATABASECHANGELOGDATABASECHANGELOGLOCK,分別記錄changelog的執行日誌和鎖日誌。工具

LiquiBase在執行changelog中的changeSet時,會首先查看DATABASECHANGELOG表,若是已經執行過,則會跳過(除非changeSet的runAlways屬性爲true,後面會介紹),若是沒有執行過,則執行並記錄changelog日誌;ui

changelog中的一個changeSet對應一個事務,在changeSet執行完後commit,若是出現錯誤則rollback;

<changeSet>標籤的主要屬性有:

  • runAlways:即便已經執行過,仍然每次都執行;注意: 因爲DATABASECHANGELOG表中還記錄了changeSet的MD5校驗值MD5SUM,若是changeSet的idname沒變,而內容變了,則因爲MD5值變了,即便runAlways的值爲True,執行也是失敗的,會報錯。這種狀況應該使用runOnChange屬性。
  • runOnChange:第一次的時候執行以及當changeSet的內容發生變化時執行。不受MD5校驗值的約束。
  • runInTransaction:是否做爲一個事務執行,默認爲true。設置爲false時須要當心:若是執行過程當中出錯了則不會rollback,數據庫極可能處於不一致的狀態;

<changeSet>下有一個重要的子標籤<rollback>,即定義回滾的SQL語句。對於create tablerename columnadd column等,LiquiBase會自動生成對應的rollback語句,而對於drop tableinsert data等則須要顯示定義rollback語句。

2.2 <include><includeAll>標籤

當changelog文件愈來愈多時,可使用<include>將文件管理起來,如:

<?xml version="1.0" encoding="utf-8"?>
<databaseChangeLog
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
    http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
    <include file="logset-20160408/0001_authorization_init.sql" relativeToChangelogFile="true"/>
</databaseChangeLog>

<include>file屬性表示要包含的changelog文件的路徑,這個文件能夠是LiquiBase支持的任意格式,relativeToChangelogFile若是爲true,則表示file屬性表示的文件路徑是相對於根changelog而不是CLASSPATH的,默認爲false。

<includeAll>指定的是changelog的目錄,而不是爲文件,如:

<includeAll path="com/example/changelogs/"/>

 

注意: 目前<include>沒有解決重複引用和循環引用的問題,重複引用還好,LiquiBase在執行的時候能夠判斷重複,而循環引用會致使無限循環,須要注意!

2.3 diff命令

diff命令用於比較數據庫之間的異同。好比經過命令行執行:

java -jar liquibase.jar --driver=com.mysql.jdbc.Driver \
    --classpath=./mysql-connector-java-5.1.29.jar \
    --url=jdbc:mysql://127.0.0.1:3306/test \
    --username=root --password=passwd \
    diff \
    --referenceUrl=jdbc:mysql://127.0.0.1:3306/authorization \
    --referenceUsername=root --referencePassword=passwd

2.4 generateChangeLog

在已有的項目上使用LiquiBase,要生成當前數據庫的changeset,能夠採用兩種方式,一種是使用數據庫工具導出SQL數據,而後changelog文件以SQL格式記錄便可;另外一種方式就是用generateChangeLog命令,如:

liquibase --driver=com.mysql.jdbc.Driver \
      --classpath=./mysql-connector-java-5.1.29.jar \
      --changeLogFile=liquibase/db.changelog.xml \
      --url="jdbc:mysql://127.0.0.1:3306/test" \
      --username=root \
      --password=yourpass \
      generateChangeLog

 

不過generateChangeLog不支持如下功能:存儲過程、函數以及觸發器;

3. Maven集成LiquiBase

3.1 liquibase-maven-plugin的配置

Maven中集成LiquiBase,主要是配置liquibase-maven-plugin,首先給出一個示例:

<plugin>
  <groupId>org.liquibase</groupId>
  <artifactId>liquibase-maven-plugin</artifactId>
  <version>3.4.2</version>
  <configuration>
      <changeLogFile>src/main/resources/liquibase/test_changelog.xml</changeLogFile>
      <driver>com.mysql.jdbc.Driver</driver>
      <url>jdbc:mysql://127.0.0.1:3306/test</url>
      <username>root</username>
      <password>passwd</password>
  </configuration>
  <executions>
      <execution>
          <phase>process-resources</phase>
          <goals>
              <goal>update</goal>
          </goals>
      </execution>
  </executions>
</plugin>

其中<configuration>節點中的配置能夠放在單獨的配置文件裏。

若是須要在父項目中配置子項目共享的LiquiBase配置,而各個子項目能夠定義本身的配置,並覆蓋父項目中的配置,則只須要在父項目的pom中將propertyFileWillOverride設置爲true便可,如:

<plugin>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-maven-plugin</artifactId>
    <version>3.4.2</version>
    <configuration>
        <propertyFileWillOverride>true</propertyFileWillOverride>
        <propertyFile>liquibase/liquibase.properties</propertyFile>
    </configuration>
</plugin>

3.2 liquibase:update

執行changelog中的變動:

$ mvn liquibase:update

3.3 liquibase:rollback

rollback有3中形式,分別是:

- rollbackCount: 表示rollback的changeset的個數;
- rollbackDate:表示rollback到指定的日期;
- rollbackTag:表示rollback到指定的tag,須要使用LiquiBase在具體的時間點打上tag;

rollbackCount比較簡單,示例如:

$ mvn liquibase:rollback -Dliquibase.rollbackCount=3

 

rollbackDate須要注意日期的格式,必須匹配當前平臺上執行DateFormat.getDateInstance()獲得的格式,好比個人格式爲MMM d, yyyy,示例如:

$ mvn liquibase:rollback -Dliquibase.rollbackDate="Apr 10, 2016"

 

rollbackTag使用tag標識,因此須要先打tag,示例如:

$ mvn liquibase:tag -Dliquibase.tag=tag20160410

而後rollback到tag20160410,如:

$ mvn liquibase:rollback -Dliquibase.rollbackTag=tag20160410
相關文章
相關標籤/搜索