6

通过Maven用LiquiBase对数据库变更进行版本控制

 3 years ago
source link: https://www.pkslow.com/archives/liquibase
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

1 LiquiBase是什么

1.1 概述与特点

LiquiBase是用于跟踪、管理和应用数据库变更的开源工具,它把数据库的变更记录在文件(xml/sql等)中,然后把变更作用到数据库中,并记录。我觉得它的主要特点:

(1)它支持多种数据库,如Oracle/MySQL/PostgreSQL/DB2等;

(2)提供数据库比较功能,把结果存在xml中,然后可基于该xml升级;

(3)会在数据库中保存修改历史,可查看记录、可支持回滚(按标签、数量和时间);已经升级的变更不会再操作;

(4)可通过maven集成,方便CI/CD

1.2 基本概念

(1)change log文件,用于记录数据库变更(changeset);可以把变更记录在xml文件、sql文件等;

(2)changeset,变更集,作为一次变更的单位,可以是新建一张表、加一列,插入数据、删除索引等。升级与回滚都是以changeset为单位的;每个changeset会通过idauthor来标记。

(3)DATABASECHANGELOG表用于记录被执行过的changeset,当回滚后,就会删去被回滚掉的记录,下表有6条记录,表示有6个changeset被执行了。记录了很多关键信息,如作者、所在文件、执行时间等。

liquibase.DATABASECHANGELOG.png

2 项目整合

LiquiBase有命令行工具,但本文主要介绍通过maven来操作。之前文章《Docker启动PostgreSQL并推荐几款连接工具》介绍了如何快速安装PostgreSQL,那我们这次就用它作为数据库。

2.1 maven配置

主要通过maven的插件来执行变更,所以要引入LiquiBase的插件,及配置相关属性如下:

<build>
  <plugins>
    <plugin>
      <groupId>org.liquibase</groupId>
      <artifactId>liquibase-maven-plugin</artifactId>
      <version>4.1.1</version>
      <configuration>
        <propertyFileWillOverride>true</propertyFileWillOverride>
        <propertyFile>target/classes/liquibase/properties/liquibase.properties</propertyFile>
      </configuration>
      <dependencies>
        <dependency>
          <groupId>org.postgresql</groupId>
          <artifactId>postgresql</artifactId>
          <version>42.2.18</version>
        </dependency>
      </dependencies>
    </plugin>
  </plugins>
</build>

这里还要引入PostgreSQL是因为需要它的数据库驱动。

2.2 属性配置文件

运行LiquiBase需要传递一些参数,如文件名、数据库连接信息等,所以liquibase.properties的内容如下:

changeLogFile:  src/main/resources/liquibase/db.changelog.xml
driver:  org.postgresql.Driver
url:  jdbc:postgresql://localhost:5432/pkslow
username:  pkslow
password:  pkslow
verbose:  true
dropFirst:  false

2.3 数据库变更文件

变更文件db.changelog.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"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd
        http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

    <changeSet  id="1"  author="larry">
        <createTable  tableName="person">
            <column  name="id"  type="int"  autoIncrement="true">
                <constraints  primaryKey="true"  nullable="false"/>
            </column>
            <column  name="firstname"  type="varchar(50)"/>
            <column  name="lastname"  type="varchar(50)">
                <constraints  nullable="false"/>
            </column>
            <column  name="state"  type="char(2)"/>
        </createTable>
        <rollback>
            <dropTable tableName="person"/>
        </rollback>
    </changeSet>

    <changeSet  id="2"  author="larry">
        <addColumn  tableName="person">
            <column  name="username"  type="varchar(8)"/>
        </addColumn>
        <rollback>
            <dropColumn tableName="person">
                <column  name="username"/>
            </dropColumn>
        </rollback>
    </changeSet>

</databaseChangeLog>

这个文件定义了两个变更集,第一个用于创建表person,第二个用于加字段username,同时提供了rollback语句以支持回滚。

准备好以上文件后,执行以下命令便可以使变更生效:

mvn clean package liquibase:update

查看数据库如下:

liquibase.simple-result.png

新建了一个person表,并有字段username

因为执行了两个变更集,所以如果我想要回滚所有变更,命令如下:

mvn liquibase:rollback -Dliquibase.rollbackCount=2

3 进阶使用

LiquiBase很强大,有很多强大的用法,这里选几个我觉得很有用的介绍一下。

3.1 执行条件判断

change log文件中,可以指定前置判断条件,如下:

<preConditions>
  <dbms  type="oracle"/> 
  <runningAs  username="pkslow"/>
</preConditions>

这样表示数据库为Oracle,数据库的用户名为pkslow才允许执行。可以防止配置错误和升级错误。

3.2 多环境属性文件

通常我们的数据库都是与多个环境对应的,如devuatprod等。我们可以通过maven的变量来指定环境:

<properties>
  <liquibase.env>dev</liquibase.env>
</properties>

<propertyFile>target/classes/liquibase/properties/liquibase.${liquibase.env}.properties</propertyFile>

默认值为dev,然后可以通过传参指定其它:

mvn clean package liquibase:update -Dliquibase.env=uat

这样它就能匹配到下面对应的文件:

liquibase.dev.properties
liquibase.uat.properties
liquibase.prod.properties

3.3 多种文件嵌套使用

LiquiBase可以嵌套文件,如xml嵌套xml文件或sql文件:

<include file="xml/pkslow.person.xml" relativeToChangelogFile="true"/>

<include file="sql/pkslow.student.sql" relativeToChangelogFile="true"/>
<include file="sql/pkslow.order.sql" relativeToChangelogFile="true"/>

其实还支持yamljson等,但我觉得还是xmlsql更适用。

3.4 多环境动态标识替换

不同数据库字段标识是不一样的,语法也会有不同,通过定义属性,能解决这个问题:

<property  name="clob.type"  value="clob"  dbms="oracle,postgresql"/> 
<property  name="clob.type"  value="longtext"  dbms="mysql"/> 
<property  name="table.name"  value="tableA"/> 

<changeSet  id="1"  author="joe"> 
  <createTable  tableName="${table.name}"> 
    <column  name="id"  type="int"/> 
    <column  name="column1"  type="${clob.type}"/> 
    <column  name="column2"  type="int"/> 
  </createTable> 
</changeSet> 

3.5 密码加密

把数据库密码以明文形式配置在文件中不是什么好习惯,LiquiBase提供了替换属性类的功能,可以用来实现加密解密:

<configuration>
  <propertyFileWillOverride>true</propertyFileWillOverride>
  <propertyFile>target/classes/liquibase/properties/liquibase.${liquibase.env}.properties</propertyFile>
  <propertyProviderClass>com.pkslow.liquibase.PkslowLiquibaseProperties</propertyProviderClass>
</configuration>

propertyProviderClass就是用来加密的类,如下:

package com.pkslow.liquibase;

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import java.util.Properties;

public class PkslowLiquibaseProperties extends Properties {

    private static final StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
    static {
        System.out.println("init for encryptor");
        //设置密钥
        encryptor.setPassword("pkslow-salt");
        //设置加密算法
        encryptor.setAlgorithm("PBEWithMD5AndTripleDES");
    }

    @Override
    public synchronized Object put(Object key, Object value) {
        if ("password".equals(key)) {
            value = encryptor.decrypt((String) value);
        }
        return super.put(key, value);
    }
}

如果想,还可以加密其它字段。

3.6 强大的回滚能力

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

# 按数量回滚,2表示回滚两个changeset
mvn liquibase:rollback -Dliquibase.rollbackCount=2
# 按日期回滚
mvn liquibase:rollback "-Dliquibase.rollbackDate=Jun 03, 2017"
# 按标签回滚
mvn liquibase:rollback -Dliquibase.rollbackTag=V1.0

这里我觉得最实用的是按标签回滚功能。

每次版本升级,就打上一个标签,如V1.0V1.1V2.0等,如果有问题,就回滚至对应标签(版本)。添加标签命令如下:

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

我把三个文件分三次升级,打了三个tag如下:

liquibase.tag.png

现在回滚到V1.1如下:

mvn liquibase:rollback -Dliquibase.rollbackTag=V1.1

结果如下:

liquibase.rollback-tag.png

相信本文能帮助大家理解和使用LiquiBase,代码请查看:https://github.com/LarryDpk/pkslow-samples


参考资料:

Jasypt加密:如何使用优秀的加密库Jasypt来保护你的敏感信息?

XML标签:https://docs.liquibase.com/change-types/community/home.html

多种格式参考:Changelog

maven整合指导:Maven

另一种整合方式,把密码信息保存在settings.xml里:Liquibase with Maven

其它用法:The Magic of Using XML Changelogs in Liquibase

参数参考:LiquiBase 管理数据库变更实践


欢迎关注微信公众号<南瓜慢说>,将持续为你更新...

file

推荐阅读:
如何制定切实可行的计划并好好执行
容器技术(Docker-Kubernetes)
SpringBoot-Cloud相关
Https专题


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK