Skip to content

一、概述

LiquiBase(从 2006 年开始投入使用)是一种免费开源的工具,可以实现不同数据库版本之间的迁移(参见 参考资料)。目前也存在少量其他开源数据库迁移工具,包括 openDBcopy 和 dbdeploy。LiquiBase 支持 10 种数据库类型,包括 DB2、Apache Derby、MySQL、PostgreSQL、Oracle、Microsoft®SQL Server、Sybase 和 HSQL。

通过日志文件的形式记录数据库的变更,然后执行日志文件中的修改,将数据库更新或回滚到一致的状态。它的目标是提供一种数据库类型无关的解决方案,通过执行schema类型的文件来达到迁移。

1.1 自动生成表结构

-Databasechangelog:记录的是每一次表修改的记录,里面会详细记录操作的类型和操作

---Databasechangeloglock表用于确保两台计算机不会同时尝试修改数据库。

1.2 配置注意事项

同一个文件中,changeSet中的id不能重复,

每次数据库变更,都会在databasechangelog生成一条记录

1.3 参考博客

Liquibase高阶使用 - 东方1024 - 博客园 (cnblogs.com)

二、使用示例

2.1 与springboot集成

依赖

xml
<!--Liquibase-->
<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-core</artifactId>
</dependency>

配置

java
import liquibase.integration.spring.SpringLiquibase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;

import javax.sql.DataSource;

/**
 * @Classname LiuqiubaseConfig
 * @Description TODO
 */
@Configuration
public class LiuqiubaseConfig {
    @Value("${spring.application.name}")
    private String applicationName;
    @Autowired
    private DataSource dataSource;


    @Bean("liquibase")
    public SpringLiquibase createLiquibase( ) {
        SpringLiquibase liquibase = new SpringLiquibase();
        // 用户模块Liquibase文件路径
        liquibase.setChangeLog("classpath:sql/" + applicationName + "/master.xml");
        liquibase.setDataSource(dataSource);
        liquibase.setShouldRun(true);
        liquibase.setResourceLoader(new DefaultResourceLoader());
        // 覆盖Liquibase changelog表名
        liquibase.setDatabaseChangeLogTable(applicationName + "_changelog_table");
        liquibase.setDatabaseChangeLogLockTable(applicationName + "_changelog_lock_table");
        return liquibase;
    }
}

在resorces中添加liquibase路径文件夹,然后创建changelog文件夹,在changeelog文件创建xml文件,然后书写操作数据库的sql或配置

sql脚本配置

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"
        xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
        xmlns:pro="http://www.liquibase.org/xml/ns/pro"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
		http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd
		http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd
		http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd">
    <!-- 将属性设置为的值  不同数据库字段标识是不一样的,语法也会有不同,通过定义属性 使用通过${}  -->
    <property  name="clob.type"  value="clob"  dbms="oracle,postgresql"/>
    <property  name="clob.type"  value="longtext"  dbms="mysql"/>
    <property  name="table.name"  value="tableA"/>

    <!-- 先决条件可以应用于整个changelog或单个changeSet。如果先决条件失败,liquibase将停止执行。  -->
    <!-- 表示数据库为Oracle,数据库的用户名为SYSTEM才允许执行上述databasechangelog  -->
    <!-- 可以使用可嵌套<and>、<or>和<not>标签将条件逻辑应用于preConditions。如果未指定条件标签,则默认为 <AND>。  -->
    <preConditions>
        <dbms type="mysql" />
        <runningAs username="root" />
    </preConditions>

    <changeSet id="1" author="Liquibase">
        <createTable tableName="test_table">
            <column name="test_id" type="int">
                <constraints primaryKey="true"/>
            </column>
            <column name="test_column" type="varchar(20)"/>
        </createTable>
    </changeSet>




    <!-- 仅当"oldtable"中没有值时,它才会运行 dropTable命令,可以防止配置错误和升级错误。
    expectedResult 这个值与SQL的执行结果作比较  -->
    <!--
    onFail: 当proConditions遇到失败的时候如何处理
    onError:当proConditions遇到错误的时候如何处理
    onUpdateSQL:自版本1.9.5后当proConditions遇到更新SQL模型的时候如何处理
    onFailMessage:自2.0起,在proConditions失败时要输出的自定义消息。
    onErrorMessage:在proConditions错误时要输出的自定义消息。
    -->
    <changeSet id="2" author="Liquibase">
        <createTable tableName="oldtable">
            <column name="test_id" type="int">
                <constraints primaryKey="true"/>
            </column>
            <column name="test_column" type="varchar(20)"/>
        </createTable>
    </changeSet>
    <changeSet id="3" author="Liquibase">
        <preConditions onFail="WARN">
            <sqlCheck expectedResult="0">select count(*) from oldtable</sqlCheck>
        </preConditions>
        <comment>Comments should go after preCondition. </comment>
        <dropTable tableName="oldtable"/>
    </changeSet>

    <!--
    1:includeAll 标签可以把一个文件夹下的所有 changelog 都加载进来。如果单个加载可以用 include。
    2:includeAll 标签里有两个属性:path 和 relativeToChangelogFile。
        2.1:path (在 include 标签里是 file):指定要加载的文件或文件夹位置
        2.2:relativeToChangelogFile :文件位置的路径是否相对于 root changelog 是相对路径,默认 false,即相对于 classpath 是相对路径。
    -->
<!--    <includeAll path="./sql/" relativeToChangelogFile="true"/>-->

    <!-- 创建表
     <createTable>表是创建表   tableName 表名
     <column>  字段标签,
        name:字段名称
        type:字段类型
        encoding:编码类型
        remarks:字段注释
    <constraints> 主键标签
        primaryKey:是否主键
        Nullable:是否为空
     -->
    <changeSet id="4" author="Liquibase">
        <createTable tableName="project_info">
            <column name="project_id" type="varchar(64)" encoding="utf8" remarks="项目id">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="project_name" type="varchar(255)" encoding="utf8" remarks="项目名字"/>
        </createTable>
    </changeSet>

    <!-- 添加列
     <addColumn>  tableName 修改表名
        <column>  字段标签,
            name:字段名称
            type:字段类型
     -->
    <changeSet id="5" author="Liquibase">
        <addColumn tableName="project_info">
            <column name="address"  type="varchar(255)" encoding="utf8" remarks="地址"/>
            <column name="project_status"  type="varchar(255)" encoding="utf8" remarks="地址"/>
        </addColumn>
    </changeSet>

    <!-- 删除列
         -->
    <changeSet id="6" author="Liquibase">
        <dropColumn tableName="project_info" columnName="address"/>
    </changeSet>

    <!-- 修改表,通过sql脚本
         -->
    <changeSet id="9" author="yunshan">
        <sqlFile path="sql/liuqiubase/sql/test_stu.sql"/>
    </changeSet>

    <!-- 插入数据
    <inSert>数据插入标签
        <column>  字段标签,
            name:字段名称
            valueNumeric:对应的字符值
         -->
    <changeSet id="7" author="Liquibase">
        <insert tableName="project_info">
            <column name="project_id" valueNumeric="312223"/>
            <column name="project_status" valueNumeric="322434343"/>
            <column name="project_name" value="wkn"/>
        </insert>
    </changeSet>


    <!-- 创建索引
    <createIndex>创建索引标签
      indexName:索引名称
      tableName:表名
        <column>  name 字段标签,
         -->
    <changeSet author="Liquibase" id="8">
        <createIndex indexName="Reft_userinfo88" tableName="project_info">
            <column name="project_status"/>
        </createIndex>
    </changeSet>
</databaseChangeLog>

三、标签介绍

3.1 databaseChangeLog标签

liquibase的入口文件,这个标签可以引入你的版本修改文件。

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"
        xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
        xmlns:pro="http://www.liquibase.org/xml/ns/pro"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
		http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd
		http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd
		http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd">
</databaseChangeLog>

子标签

tagDescription
preConditions执行sql变更文件的前置条件
property设置的属性的值
changeSet要执行的更改
include包含要执行的更改集的附加文件
context上下文将被附加到(使用AND)所有变更集

3.2 preConditions标签

可以应用于<databaseChangeLog>标签或者<changeSet>标签。

先决条件可以应用于整个changelog或单个changeSet。如果先决条件失败,liquibase将停止执行。

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.8.xsd">
    <!-- 只有在Oracle数据库以及用户是SYSTEM时才会执行。-->
    <preConditions>
        <dbms type="oracle" />
        <runningAs username="SYSTEM" />
    </preConditions>
    
    <changeSet id="1" author="bob">
        <preConditions onFail="WARN">
            <sqlCheck expectedResult="0">select count(*) from oldtable</sqlCheck>
        </preConditions>
        <comment>Comments should go after preCondition. If they are before then liquibase usually gives error.</comment>
        <dropTable tableName="oldtable"/>
    </changeSet>
</databaseChangeLog>

preConditions前置条件分为正常和异常情况: 正常情况下,无论返回的值是不是预料的值(0),oldtable都会被删除,只是如果不是预料的值,这里会给出WARN; 异常情况下,也就是如果oldtable不存在,删除oldtable的命令将不会执行。

处理失败和错误

AttributeDescription
onFail当preConditions是失败情形下如何处理
OnError当preConditions是错误情形下如何处理
onSqlOutput在updateSQL模式下要做什么
onFailMessage输出的失败信息
onErrorMessage输出的错误信息

OnFail/OnError值可能配置的值

ValueDescription
HALT立即停止执行整个更改日志。 [默认]
CONTINUE跳过* changeSet 。 下次更新时将再次尝试执行更改集。 继续 changelog *
MARK_RAN跳过更改集,但将其标记为已执行。继续更改日志。
WARN输出警告并继续照常执行* changeSet * / * changelog *。

onSqlOutput可能配置的值

ValueDescription
TEST在updateSQL模式下运行changeSet
FAIL使preConditons在updateSQL模式下失败
IGNORE忽略updateSQL模式中的preConditons(默认)。

and/or/not逻辑

使用nestable <and><or><not>标记将条件逻辑应用于前置条件。如果没有指定条件标记,则默认为AND。

复合条件,例如,是oracle数据库,并且用户必须是SYSTEM 或者 数据库是mysql,且用户需要为root时

xml
<preConditions>
     <or>
         <and>
            <dbms type="oracle" />
            <runningAs username="SYSTEM" />
         </and>
         <and>
            <dbms type="mysql" />
            <runningAs username="root" />
         </and>
     </or>
 </preConditions>

可用的preConditions子标签

xml
<dbms>:如果针对指定类型执行的数据库匹配,则可以传递。
<dbms type="mysql" />

<runningAs>:执行执行的用户,匹配才可以传递。
<runningAs username="root" />

<changeSetExecuted>:如果指定的changeSet被执行了才可以传递。
<changeSetExecuted id="1" author="YoungLu" changeLogFile="classpath:liquibase/changelog/2020-02-11-change.xml" />

<columnExists>:如果数据库中的指定列存在则传递
<columnExists schemaName="young_webchat" tableName="y_user" columnName="username" />

<tableExists>:如果数据库中的表存在,则传递
<tableExists schemaName="young_webchat" tableName="y_user" />

<viewExists>:如果数据库中的视图存在,则传递
<viewExists schemaName="young_webchat" viewName="y_user_view" />

<foreignKeyConstraintExists>:如果外键存在则传递
<foreignKeyConstraintExists schemaName="young_webchat" foreignKeyName="y_user_log_fk" />

<indexExists>:如果索引存在则传递
<indexExists schemaName="young_webchat" indexName="y_user_idx" />

<sequenceExists>:如果序列存在则传递
<sequenceExists schemaName="young_webchat" sequenceName="y_user_seq" />

<primaryKeyExists>:如果主键存在则传递
<primaryKeyExists schemaName="young_webchat" primaryKeyName="y_user_id" />

<sqlCheck>:执行SQL检查。SQL必须返回具有单个值的单个行。
<sqlCheck expectedResult="1">SELECT COUNT(1) FROM pg_tables WHERE TABLENAME = 'myRequiredTable'</sqlCheck>

<changeLogPropertyDefined>:检查给定的changelog参数是否存在。如果一个值也是给定的,如果这个值与给定的值不相同那么它只会失败。
<changeLogPropertyDefined property="myproperty"/>
<changeLogPropertyDefined property="myproperty" value="requiredvalue"/>

<customPrecondition>:可以通过创建实现liquibase.precondition的类来创建自定义前置条件。CustomPrecondition接口。自定义类的参数是通过基于子标记的反射设置的。参数作为字符串传递给自定义前置条件。

<customPrecondition className="com.example.CustomTableCheck">
    <param name="tableName" value="our_table"/>
    <param name="count" value="42"/>
</customPrecondition>

3.3 Properties标签

为changelog定义一个参数。给定上下文 和/或 数据库的列表,该参数将仅在这些上下文 和/或 数据库中使用。

xml
<property name="clob.type" value="clob" dbms="oracle"/>
<property name="clob.type" value="longtext" dbms="mysql"/>

可用的配置项

AttributeDescription
name表的数据库名称
value所需列的表的名称
context上下文,逗号分隔
dbms要用于该changeSet 的数据库的类型。关键字all和none也可用。
global定义属性是全局的还是局限于databaseChangeLog。“true”或“false”

数据库兼容配置

xml
	<property name="autoIncrement" value="true" dbms="mysql" global="true"/>

    <!--clob类型-->
    <property name="clob.type" value="longtext" dbms="mysql"/>
    <property name="clob.type" value="clob" dbms="oracle, mssql, mariadb, postgresql"/>

    <!--int,还是不建议用,因为oracle和sql server 很难表示对应的4 294 967 295-->
    <property name="int_unsigned" value="int unsigned" dbms="mysql" global="true"/>
    <property name="int_unsigned" value="int" dbms="oracle, mssql" global="true"/>

    <!--tinyint可以直接用,但是mysql的数值范围是-128到127, oracle和sql server则是 0到255 -->
    <!--tinyint_unsigned-->
    <property name="tinyint_unsigned" value="tinyint unsigned" dbms="mysql" global="true"/>
    <property name="tinyint_unsigned" value="tinyint" dbms="mssql" global="true"/>
    <property name="tinyint_unsigned" value="Number(3, 0)" dbms="oracle" global="true"/>

    <!--boolean,没必要写boolean的兼容配置,想用的话直接用boolean就可以,liquibase会自动处理好-->
    <property name="boolean" value="tinyint" dbms="mysql" global="true"/>
    <property name="boolean" value="number(1, 0)" dbms="oracle" global="true"/>
    <property name="boolean" value="bit" dbms="mssql" global="true"/>

    <!-- Long整型存储 -->
    <property name="bigint" value="bigint" dbms="mysql" global="true"/>
    <property name="bigint" value="number(20,0)" dbms="oracle,mssql" global="true"/>

    <!-- Nvarchar兼容配置 -->
    <property name="nvarchar" value="varchar" dbms="mysql" global="true"/>
    <property name="nvarchar" value="nvarchar" dbms="oracle,mssql" global="true"/>

    <!--float-->
    <property name="floatType" value="float4" dbms="postgresql, h2"/>
    <property name="floatType" value="float" dbms="mysql, oracle, mssql, mariadb"/>

    <!-- 当前日期 -->
    <property name="now" value="now()" dbms="h2"/>
    <property name="now" value="now()" dbms="mysql"/>
    <property name="now" value="getutcdate()" dbms="mssql"/>
    <property name="now" value="sysdate" dbms="oracle"/>

    <property name="uuidType" value="varchar(36)" dbms="h2, mysql, mariadb"/>
    <property name="sequenceSchemaName" value="YHY" dbms="oracle, mssql"/>

3.4 changeSet标签

主要由“id” 、“author”、changelog文件路径名组成

可用的属性值

属性描述
id唯一识别,不一定是数字
author作者
dbms数据库类型
runAlways在每次运行时执行changeset ,即使之前已经运行过
runOnChange在第一次看到更改时执行更改,并且在每次changeset 时执行更改
context控制是否执行changeset,这取决于运行时设置。任何字符串都可以用于上下文名称,它们被不区分大小写地选中。
labels控制是否执行changeset,这取决于运行时设置。任何字符串都可以用于标签名称,并且不区分大小写地选中它们。
runInTransaction是否应该将changeset作为单个事务运行(如果可能的话)?默认值为true。
failOnError如果在执行changeset时发生错误,迁移是否应该失败
objectQuotingStrategy这控制了在生成的SQL中如何引用对象名,或者在对数据库的调用中如何使用对象名。不同的数据库对对象的名称执行不同的操作,例如Oracle将所有内容都转换为大写(除非使用引号)。有三个可能的值。默认值是LEGACY。三个配置的值: LEGACY - Same behavior as in Liquibase 2.0 QUOTE_ALL_OBJECTS - 每个对象都加上双引号 :person becomes “person”.QUOTE_ONLY_RESERVED_WORDS - 在保留关键字和可用列名上面加双引号

可用的子标签

1)comment

注释

2)preConditions

前置条件,例如做一些不可逆操作前的必要检查

3)Any Refactoring Tag(s)

<Any Refactoring Tag(s)>要作为这个更改集的一部分运行的数据库更改

4)validCheckSum

添加一个校验和,不管数据库中存储了什么,它都被认为对这个changeset是有效的。主要用于需要更改changeset,并且不希望在已经运行了changeset的数据库上抛出错误(不推荐使用此过程)

5)rollback

描述如何回滚更改集的SQL语句或重构标记

rollback标签的示例:

xml
 <changeSet id="1" author="bob">
    <createTable tableName="testTable">
    <rollback>
        drop table testTable
    </rollback>
</changeSet>
<changeSet id="1" author="bob">
    <createTable tableName="testTable">
    <rollback>
        <dropTable tableName="testTable"/>
    </rollback>
</changeSet>
<changeSet id="2" author="bob">
    <dropTable tableName="testTable"/>
    <rollback changeSetId="1" changeSetAuthor="bob"/>
</changeSet>

这里发生了回滚,会调用id为1的changeSet 。

6)createIndex

【强制】主键索引名为pk字段名;唯一索引名为uk字段名;普通索引名则为idx字段名。 说明:pk 即primary key;uk_ 即 unique key;idx_ 即index的简称。

  • 普通索引名称以IDX为前缀。
  • 单字段索引的命名方式为:IDX表名字段名,表名无须前缀,命名长度太长时表名和字段名可以考虑缩写。
  • 多字段联合索引命名方式同单字段,考虑长度限制,可以只列出主要字段名或者采用缩写方式描述索引字段。 示例: \1. 错误命名:IDX_USER_INFO,没有给出字段名 \2. 错误命名:IDX_USER_INFO_DEPT_CODE,前缀错误。
xml
<changeSet id="20200509001" author="dongfang">
  <createIndex tableName="worker" indexName="idx_name">
    <column name="name"></column>
  </createIndex>
  <createIndex tableName="worker" indexName="idx_address_tel">
    <column name="address"></column>
    <column name="tel"></column>
  </createIndex>
</changeSet>
7)column

可以是单标签,也可以是双标签。双标签可以嵌套 <constraints /> 标签

8)addPrimaryKey
xml
  <addPrimaryKey columnNames="event_id, name" tableName="c_sys_persist_audit_evt_data"/>
9)addNotNullConstraint
xml
<addNotNullConstraint   columnName="password_hash" columnDataType="varchar(60)" tableName="c_usr_user"/>
10)addForeignKeyConstraint
xml
<addForeignKeyConstraint baseColumnNames="event_id" baseTableName="c_sys_persist_audit_evt_data" constraintName="fk_evt_pers_audit_evt_data" referencedColumnNames="event_id" referencedTableName="c_sys_persistent_audit_event"/>
11)dropDefaultValue
xml
<dropDefaultValue tableName="c_sys_common_menu" columnName="created_date" columnDataType="datetime"/>
12)loadData
xml
<loadData
          file="config/liquibase/project/user/fake-data/common_menu.csv"
          separator=";"
          tableName="c_sys_common_menu">
    <column name="id" type="numeric"/>
    <column name="created_by" type="string"/>
    <column name="created_date" type="datetime"/>
    <!-- jhipster-needle-liquibase-add-loadcolumn - JHipster (and/or extensions) can add load columns here, do not remove-->
</loadData>

3.5 include标签

将change-logs拆分为易于管理的部分。

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.8.xsd">
    <include file="com/example/news/news.changelog.xml"/>
    <include file="com/example/directory/directory.changelog.xml"/>
    
    <!--
    1:includeAll 标签可以把一个文件夹下的所有 changelog 都加载进来。如果单个加载可以用 include。
    2:includeAll 标签里有两个属性:path 和 relativeToChangelogFile。
        2.1:path (在 include 标签里是 file):指定要加载的文件或文件夹位置
        2.2:relativeToChangelogFile :文件位置的路径是否相对于 root changelog 是相对路径,默认 false,即相对于 classpath 是相对路径。
    -->
    <includeAll path="./sql/" relativeToChangelogFile="true"/>
</databaseChangeLog>

属性

AttributeDescription
file被引入的文件
relativeToChangelogFile用文件的相对路径而不是classpath
context向所有包含的changeSets追加上下文(使用AND)

3.6 Contexts标签

Liquibase 中的context是可以添加到changeSet 的标签,以控制将在任何特定的迁移运行中执行哪些设置。任何字符串都可用于上下文名称,并且它们处于不区分大小写状态。

通过任何可用方法运行迁移器时,可以传递一组要运行的context。将仅运行使用已传递上下文标记的changeset。在你迁移的时候如果没有指定一个具体的context,那么所有的context都会执行。

语法:context语法具体是使用AND,OR,!和圆括号。在没有圆括号的情况下,操作的顺序是!,AND,OR

context="!test"
context="v1.0 or map"
context="v1.0 or map"
context="!qa and !master"

使用 , 来分隔上下文的工作方式类似于 OR 操作,但具有最高的优先级。

"test,qa"`等价于`test OR qa`
`"test,qa and master"`等价于`test OR (qa AND master)

3.7 Rollback标签

回滚标记描述如何对 SQL 语句、change tag或以前的changeSet的引用进行回滚更改。

多个语句可以被包含在一个<rollback>标签中。一个changeSet中可以有多个rollback标签

DATABASECHANGELOG表用于记录被执行过的changeset,当回滚后,就会删去被回滚掉的记录。

版本回滚 可以使用命令行 或者 maven ,ant 等构建工具来完成。

xml
<changeSet id="changeRollback" author="nvoxland">
    <createTable tableName="changeRollback1">
        <column name="id" type="int"/>
    </createTable>
    <rollback>
        <dropTable tableName="changeRollback1"/>
    </rollback>
</changeSet>

四、数据库版本控制

4.1 更新版本

sh
# 可在pom文件中指定版本标签,执行命令会自动进行更改


<NolebasePageProperties />




mvn clean package liquibase:update
# 也可命令行指定,还可以自己添加
mvn clean package liquibase:update -Dliquibase.tag=v3.0

4.2 添加版本标签

每次版本升级,就打上一个标签,如V1.0、V2.0等,如果有问题,就回滚至对应标签(版本)

sh
# 命令行方式

mvn liquibase:tag -Dliquibase.tag=V1.1

4.3 maven配置方式

在maven中配置后执行以上更新语句会自动添加标签

xml
<execution>                 
	<phase>process-resources</phase>
	<configuration>
		<!--版本指定,也可在命令执行时指定-->
		<tag>V1.1</tag>
	</configuration>
	<goals>
		<!--执行类型-->
		<goal>update</goal>
		<goal>tag</goal>
	</goals>
</execution>

4.4 版本回滚

LiquiBase 提供了按数量、日期和标签回滚的能力,如下:

sh
# 按数量回滚,2表示回滚两个changeset
mvn liquibase:rollback -Dliquibase.rollbackCount=2
# 按日期回滚
mvn liquibase:rollback -Dliquibase.rollbackDate="2021-09-16 09:09:34"
# 按标签回滚
mvn liquibase:rollback -Dliquibase.rollbackTag=V1.0

4.5 生成回滚的sql脚本:

sh
mvn liquibase:rollbackSQL -Dliquibase.rollbackTag=v1.0

mvn liquibase:rollbackSQL -Dliquibase.rollbackDate="2021-09-16 09:09:34"

4.6 生成变更日志

对于已有项目且之前未使用过Liquibase,使用 generateChangeLog 捕获数据库的当前状态,然后将这些更改应用于数据库。提供的扩展名决定了变更日志的格式,可为YAML或JSON或SQL或XML格式。

sh
mvn liquibase:generateChangeLog
-Dliquibase.outputChangeLogFile=changelog-test.xml

**注意:**如果生成 SQL 格式的更改日志,请将目标数据库的类型名称指定为文件名的一部分,如

changelog.<db_type>.sql

4.7 对比差异

diff 允许您将相同类型或不同类型的两个数据库相互比较。

运行diff目标需要两个 URL:

referenceURL – 比较的来源。该referenceURL 属性代表您的源数据库。

URL – 比较的目标。该url 属性代表您要与源数据库进行比较的目标数据库。

sh
mvn liquibase:diff
-Dliquibase.changeLogFile=myChangeLog.xml
-Dliquibase.driver=oracle.jdbc.OracleDriver
-Dliquibase.url="jdbc:oracle:thin:@<IP OR HOSTNAME>:<PORT>:<SERVICE NAME OR SID>"
-Dliquibase.username=<USERNAME>
-Dliquibase.password=<PASSWORD>
-Dliquibase.referenceUrl="jdbc:oracle:thin:@<IP OR HOSTNAME>:<PORT>:<SERVICE NAME OR SID>"
-Dliquibase.referenceUsername=<USERNAME>
-Dliquibase.referencePassword=<PASSWORD>

生成将源数据库与目标数据库进行比较后应用更改的更改日志

生成将源数据库与目标数据库进行比较后应用更改的更改日志

sh
mvn liquibase:diff -Dliquibase.diffChangeLogFile=mydiff.xml

Liquibase允许您使用diffTypes 属性来过滤要比较的对象类型。可以将多个过滤器作为逗号分隔列表添加到属性中。如果没有diffTypes指定,则考虑所有对象。

sh
mvn liquibase:diff -Dliquibase.diffTypes=tables,indexes,views

更多maven命令可查看:https://docs.liquibase.com/tools-integrations/maven/commands/home.html

五、liquibase 命令附录

更多命令可查看官方文档:https://docsstage.liquibase.com/commands/home.html

命令名称命令描述
update更新数据库到当前版本
updateSQL写入SQL将数据库更新到currentversion或STDOUT
updateCount将本地num个未执行的changeset更改应用到数据库
updateCountSQL将本地num个未执行的changeset输出到sql文件
updateToTag更新数据库到指定tag的changeset
updateToTagSQL更新数据库到指定tag的changeset输出到sql文件
rollback将数据库回滚到指定标签的状态
rollbackSQL将数据库回滚到指定标签的状态的sql
rollbackToDate <date/time>将数据库回滚到给定日期/时间的状态。日期格式为YYYY-MM-DD HH:MM:SS或YYYY-MM-DD'T'HH:MM:SS,但可以仅指示日期或时间。
rollbackToDateSQL <date/time>写入SQL以将数据库回滚到给定日期/时间版本的状态到STDOUT
rollbackCount回滚最近num个changeset
rollbackCountSQL回滚最近num个changeset输出到sql
futureRollbackSQL执行rollback标签里边的sql
futureRollbackSQL输出rollback里边的sql到sql文件
futureRollbackFromTagSQL输出指定tag的回滚sql
updateTestingRollback回滚更新数据库,然后再次回滚更改。用于测试回滚支持
generateChangeLog写入更改日志XML以将数据库的当前状态复制到标准输出
snapshot将数据库的当前状态写入标准输出
snapshotReference将referenceUrl数据库的当前状态写入标准输出
Diff Commands数据库对比命令
diff [diff parameters]数据库对比命令
diffChangeLog [diff parameters]数据库对比日志
Documentation Commands生成文档命令
dbDoc基于当前数据库和更改日志生成类似javadoc的文档
Maintenance Commands维护命令
tag给当前的数据库打标签,(只会打最新的一条记录的tag)
tagExists检查对应的标签是否存在
status [–verbose]输出为执行changeset的行数
unexpectedChangeSets[–verbose]输出本地不存在changeset 行数
validate检查是否有错误的changelog
calculateCheckSum检查指定changeset id 的checksum值 格式为 filepath:🆔:author
clearCheckSums从数据库日志中删除所有保存的校验和
changelogSync标记所有的更改已执行
changelogSyncSQL生成标记更改已执行的sql并输出到标准输出
markNextChangeSetRan将下一个变更标记为已执行
markNextChangeSetRanSQL生成将下一个变更标记为已执行的sql并输出到标准输出
listLocks列出liquibase数据库锁
releaseLocks释放所有的liquibase数据库锁
dropAll删除数据库表(慎用!)

六、完整数据列表

6.1 boolean

数据库类型
MySQLBIT(1)
MSSQLbit
OracleNUMBER(1)
SQLiteBOOLEAN
H2BOOLEAN
PostgresDatabaseBOOLEAN
UnsupportedBOOLEAN
DB2SMALLINT
HsqlBOOLEAN
FirebirdDatabaseSMALLINT
DerbyDatabaseSMALLINT
InformixDatabaseBOOLEAN
SybaseDatabaseBIT
SybaseASADatabaseBIT

6.2 tinyint

数据库类型
MySQLTINYINT
MSSQLTINYINT
OracleNUMBER(3)
SQLiteTINYINT
H2TINYINT
PostgresDatabaseSMALLINT
UnsupportedTINYINT
DB2SMALLINT
HsqlTINYINT
FirebirdDatabaseSMALLINT
DerbyDatabaseSMALLINT
InformixDatabaseTINYINT
SybaseDatabaseTINYINT
SybaseASADatabaseTINYINT

6.3 int

数据库类型
MySQLint
MSSQLint
OracleINTEGER
SQLiteINTEGER
H2int
PostgresDatabaseint
Unsupportedint
DB2INTEGER
Hsqlint
FirebirdDatabaseint
DerbyDatabaseINTEGER
InformixDatabaseint
SybaseDatabaseint
SybaseASADatabaseint

6.4 mediumint

数据库类型
MySQLMEDIUMINT
MSSQLint
OracleMEDIUMINT
SQLiteMEDIUMINT
H2MEDIUMINT
PostgresDatabaseMEDIUMINT
UnsupportedMEDIUMINT
DB2MEDIUMINT
HsqlMEDIUMINT
FirebirdDatabaseMEDIUMINT
DerbyDatabaseMEDIUMINT
InformixDatabaseMEDIUMINT
SybaseDatabaseMEDIUMINT
SybaseASADatabaseMEDIUMINT

6.5 bigint

数据库类型
MySQLBIGINT
MSSQLBIGINT
OracleNUMBER(38,0)
SQLiteBIGINT
H2BIGINT
PostgresDatabaseBIGINT
UnsupportedBIGINT
DB2BIGINT
HsqlBIGINT
FirebirdDatabaseBIGINT
DerbyDatabaseBIGINT
InformixDatabaseINT8
SybaseDatabaseBIGINT
SybaseASADatabaseBIGINT

6.6 float

数据库类型
MySQLFLOAT
MSSQLFLOAT
OracleFLOAT
SQLiteFLOAT
H2FLOAT
PostgresDatabaseFLOAT
UnsupportedFLOAT
DB2FLOAT
HsqlFLOAT
FirebirdDatabaseFLOAT
DerbyDatabaseFLOAT
InformixDatabaseFLOAT
SybaseDatabaseFLOAT
SybaseASADatabaseFLOAT

6.7 double

数据库类型
MySQLDOUBLE
MSSQL[float](53)
OracleFLOAT(24)
SQLiteDOUBLE
H2DOUBLE
PostgresDatabaseDOUBLE
UnsupportedDOUBLE
DB2DOUBLE
HsqlDOUBLE
FirebirdDatabaseDOUBLE PRECISION
DerbyDatabaseDOUBLE
InformixDatabaseDOUBLE PRECISION
SybaseDatabaseDOUBLE
SybaseASADatabaseDOUBLE

6.8 decimal

数据库类型
MySQLDECIMAL
MSSQL[decimal](18,0)
OracleDECIMAL
SQLiteDECIMAL
H2DECIMAL
PostgresDatabaseDECIMAL
UnsupportedDECIMAL
DB2DECIMAL
HsqlDECIMAL
FirebirdDatabaseDECIMAL
DerbyDatabaseDECIMAL
InformixDatabaseDECIMAL
SybaseDatabaseDECIMAL
SybaseASADatabaseDECIMAL

6.9 number

数据库类型
MySQLnumeric,经测试会是decimal(10, 0)
MSSQL[numeric](18,0)
OracleNUMBER
SQLiteNUMBER
H2NUMBER
PostgresDatabasenumeric
UnsupportedNUMBER
DB2numeric
Hsqlnumeric
FirebirdDatabasenumeric
DerbyDatabasenumeric
InformixDatabasenumeric
SybaseDatabasenumeric
SybaseASADatabasenumeric

6.10 blob

数据库类型
MySQLLONGBLOB,经测试是blob
MSSQL[varbinary](MAX)
OracleBLOB
SQLiteBLOB
H2BLOB
PostgresDatabaseBYTEA
UnsupportedBLOB
DB2BLOB
HsqlBLOB
FirebirdDatabaseBLOB
DerbyDatabaseBLOB
InformixDatabaseBLOB
SybaseDatabaseIMAGE
SybaseASADatabaseLONG BINARY

6.11 clob

数据库类型
MySQLLONGTEXT
MSSQL[varchar](MAX)
OracleCLOB
SQLiteTEXT
H2CLOB
PostgresDatabaseTEXT
UnsupportedCLOB
DB2CLOB
HsqlCLOB
FirebirdDatabaseBLOB
DerbyDatabaseCLOB
InformixDatabaseCLOB
SybaseDatabaseTEXT
SybaseASADatabaseLONG VARCHAR

6.12 function

数据库类型
MySQLFUNCTION
MSSQL[function]
OracleFUNCTION
SQLiteFUNCTION
H2FUNCTION
PostgresDatabaseFUNCTION
UnsupportedFUNCTION
DB2FUNCTION
HsqlFUNCTION
FirebirdDatabaseFUNCTION
DerbyDatabaseFUNCTION
InformixDatabaseFUNCTION
SybaseDatabaseFUNCTION
SybaseASADatabaseFUNCTION

6.13 UNKNOWN

数据库类型
MySQLUNKNOWN
MSSQL[UNKNOWN]
OracleUNKNOWN
SQLiteUNKNOWN
H2UNKNOWN
PostgresDatabaseUNKNOWN
UnsupportedUNKNOWN
DB2UNKNOWN
HsqlUNKNOWN
FirebirdDatabaseUNKNOWN
DerbyDatabaseUNKNOWN
InformixDatabaseUNKNOWN
SybaseDatabaseUNKNOWN
SybaseASADatabaseUNKNOWN

6.14 datetime

数据库类型
MySQLdatetime
MSSQL[datetime]
OracleTIMESTAMP
SQLiteTEXT
H2TIMESTAMP
PostgresDatabaseTIMESTAMP WITHOUT TIME ZONE
Unsupporteddatetime
DB2TIMESTAMP
HsqlTIMESTAMP
FirebirdDatabaseTIMESTAMP
DerbyDatabaseTIMESTAMP
InformixDatabaseDATETIME年份分数(5)
SybaseDatabasedatetime
SybaseASADatabasedatetime

6.15 time

数据库类型
MySQLtime
MSSQL[time](7)
OracleDATE
SQLitetime
H2time
PostgresDatabaseTIME WITHOUT TIME ZONE
Unsupportedtime
DB2time
Hsqltime
FirebirdDatabasetime
DerbyDatabasetime
InformixDatabaseINTERVAL HOUR TO FRACTION(5)
SybaseDatabasetime
SybaseASADatabasetime

6.16 timestamp

数据库类型
MySQLtimestamp
MSSQL[datetime]
OracleTIMESTAMP
SQLiteTEXT
H2TIMESTAMP
PostgresDatabaseTIMESTAMP WITHOUT TIME ZONE
Unsupportedtimestamp
DB2timestamp
HsqlTIMESTAMP
FirebirdDatabaseTIMESTAMP
DerbyDatabaseTIMESTAMP
InformixDatabaseDATETIME年份分数(5)
SybaseDatabasedatetime
SybaseASADatabasetimestamp

6.17 date

数据库类型
MySQLdate
MSSQL[date]
Oracledate
SQLitedate
H2date
PostgresDatabasedate
Unsupporteddate
DB2date
Hsqldate
FirebirdDatabasedate
DerbyDatabasedate
InformixDatabasedate
SybaseDatabasedate
SybaseASADatabasedate

6.18 char

数据库类型
MySQLCHAR
MSSQL[char](1)
OracleCHAR
SQLiteCHAR
H2CHAR
PostgresDatabaseCHAR
UnsupportedCHAR
DB2CHAR
HsqlCHAR
FirebirdDatabaseCHAR
DerbyDatabaseCHAR
InformixDatabaseCHAR
SybaseDatabaseCHAR
SybaseASADatabaseCHAR

6.19 varchar

数据库类型
MySQLVARCHAR
MSSQL[varchar](1)
OracleVARCHAR2
SQLiteVARCHAR
H2VARCHAR
PostgresDatabaseVARCHAR
UnsupportedVARCHAR
DB2VARCHAR
HsqlVARCHAR
FirebirdDatabaseVARCHAR
DerbyDatabaseVARCHAR
InformixDatabaseVARCHAR
SybaseDatabaseVARCHAR
SybaseASADatabaseVARCHAR

6.20 nchar

数据库类型
MySQLNCHAR
MSSQL[nchar](1)
OracleNCHAR
SQLiteNCHAR
H2NCHAR
PostgresDatabaseNCHAR
UnsupportedNCHAR
DB2NCHAR
HsqlNCHAR
FirebirdDatabaseNCHAR
DerbyDatabaseNCHAR
InformixDatabaseNCHAR
SybaseDatabaseNCHAR
SybaseASADatabaseNCHAR

6.21 nvarchar

数据库类型
MySQLNVARCHAR,经测试,mysql还是用的varchar,但是mysql的varchar就相当于nvarchar
MSSQL[nvarchar](1)
OracleNVARCHAR2
SQLiteNVARCHAR
H2NVARCHAR
PostgresDatabaseNVARCHAR
UnsupportedNVARCHAR
DB2NVARCHAR
HsqlVARCHAR
FirebirdDatabaseNVARCHAR
DerbyDatabaseVARCHAR
InformixDatabaseNVARCHAR
SybaseDatabaseNVARCHAR
SybaseASADatabaseNVARCHAR

6.22 currency

数据库类型
MySQLDECIMAL
MSSQL[money]
OracleNUMBER(15,2)
SQLiteREAL
H2DECIMAL
PostgresDatabaseDECIMAL
UnsupportedDECIMAL
DB2DECIMAL(19,4)
HsqlDECIMAL
FirebirdDatabaseDECIMAL(18,4)
DerbyDatabaseDECIMAL
InformixDatabaseMONEY
SybaseDatabaseMONEY
SybaseASADatabaseMONEY

6.23 uuid

数据库类型
MySQLchar(36)
MSSQL[uniqueidentifier]
OracleRAW(16)
SQLiteTEXT
H2UUID
PostgresDatabaseUUID
Unsupportedchar(36)
DB2char(36)
Hsqlchar(36)
FirebirdDatabasechar(36)
DerbyDatabasechar(36)
InformixDatabasechar(36)
SybaseDatabaseUNIQUEIDENTIFIER
SybaseASADatabaseUNIQUEIDENTIFIER