现在的位置: 首页Mysql, Storage, tools>正文
数据库版本管理工具Liquibase
2016年05月24日 Mysql, Storage, tools 暂无评论 ⁄ 被围观 2,332 view+

LiquiBase是一个用于数据库重构和迁移的开源工具,通过日志文件的形式记录数据库的变更,然后执行日志文件中的修改,将数据库更新或回滚到一致的状态。LiquiBase的主要特点有:

  • 支持几乎所有主流的数据库,如MySQL, PostgreSQL, Oracle, Sql Server, DB2等
  • 支持多开发者的协作维护
  • 日志文件支持多种格式,如XML, YAML, JSON, SQL等
  • 支持多种运行方式,如命令行、Spring集成、Maven插件、Gradle插件等

本文首先简单介绍一下LiquiBase的changelog文件的常用标签配置,然后讲解在Maven中集成并运行LiquiBase。

1. 安装

  1. 安装java 1.7 ,下载jdk包解压,设置环境变量即可
  2. 安装liquibase,下载解压即可。
  3. 安装maven,下载解压,设置环境变量即可(liquibase可以不配合maven单独运行)。
//linux下环境变量设置如下:
export JAVA_HOME=/usr/local/jdk1.7.0_79
export JRE_HOME=/usr/local/jdk1.7.0_79/jre
export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
export M2_HOME=/usr/local/maven-3.3.9
export PATH=$PATH:$JAVA_HOME/bin:$M2_HOME/bin:/usr/local/liquibase

2. 使用

要开始使用 LiquiBase,需要以下四个步骤:

  1. 创建一个数据库 变更日志(change log)文件
  2. 在变更日志文件内部创建一个 变更集(change set)
  3. 检验数据库中的变更
  4. 创建一个变更日志和变更集

要运行 LiquiBase,首先要创建一个数据库变更日志文件,我们采取SQL格式来创建。

官方手册参考:http://www.liquibase.org/documentation/sql_format.html

格式化SQL文件

关于SQL语句的语法依赖于选择的数据库类型,以下语法仅适用于mysql为例。Liquibase是通过SQL注释“--”来标记标签的,每个SQL文件必须开头加入一下声明:

--liquibase formatted sql

Changesets变更集

每个变更集开始处都必须添加一些声明信息:

--changeset author:id attribute1:value1 attribute2:value2 [...]

其中,author:id是必须的,其他的参数可以使用默认值,暂不修改。每个变更集可以带一个或者多个SQL声明,默认使用“;”隔开,每个变更集生成一条对应的记录。

示例一:一个SQL文件一个changeset、一个changeset执行多条SQL语句的情况,以下示例数据库里面只会生成一条记录。

--liquibase formatted sql

--changeset icyboy_db:4007-1
CREATE TABLE table3 (
  id int(11) NOT NULL,
  name varchar(255) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=MyISAM;
ALTER TABLE  table3 CHANGE  id  id INT( 11 ) AUTO_INCREMENT;
ALTER TABLE  table3 CHANGE  name  firstname VARCHAR( 255 );
INSERT INTO table3 (id, firstname) VALUES (NULL, 'name1'),(NULL, 'name2'), (NULL, 'name3');
--rollback drop table table3;

示例二:一个SQL文件多个changeset、一个changeset执行一条SQL语句的情况。

--liquibase formatted sql

--changeset icyboy_db:4008-1
CREATE TABLE table2 (
  id int(11) NOT NULL,
  name varchar(255) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=MyISAM;
--rollback drop table table2;

--changeset icyboy_db:4008-2
ALTER TABLE  table2 CHANGE  id  id INT( 11 ) AUTO_INCREMENT;
--rollback ALTER TABLE  table2 CHANGE  id  id INT( 11 ) NOT NULL;

--changeset icyboy_db:4008-3
ALTER TABLE  table2 CHANGE  name  firstname VARCHAR( 255 );
--rollback ALTER TABLE  table2 CHANGE  firstname  name VARCHAR( 255 );

--changeset icyboy_db:4008-4
INSERT INTO table2 (id, firstname) VALUES (NULL, 'name1'),(NULL, 'name2'), (NULL, 'name3');
--rollback DELETE FROM table2 WHERE firstname IN('name1','name2','name3');

我们实际使用时候也可以是一个SQL文件多个changeset、一个changeset多个SQL,具体使用根据怎么样写对于回滚更方便,目前我们看到的是一个changeset只能执行一次回滚命令。所以,对于一个changeset多条SQL命令的情况,还不知道怎么写回滚,除非是针对一个表的操作,如上述示例一所示。

从命令行运行 LiquiBase

MySQL:

liquibase --changeLogFile=./Release0003.sql --driver=com.mysql.jdbc.Driver --classpath=./mysql-connector-java-5.1.10-bin.jar --url="jdbc:mysql://localhost/liquibaseuse?Unicode=true&characterEncoding=UTF-8" --username=test --password=123456 update

Oracle:

liquibase --changeLogFile=./Release0003.sql --driver=oracle.jdbc.OracleDriver --classpath=./ojdbc6.jar --url="jdbc:oracle:thin:@localhost:1521:liquibase" --username=test --password=123456 update

在本例中,运行 LiquiBase 传入的内容:

  1. 数据库驱动器
  2. 数据库驱动器 JAR 文件的位置所在的类路径
  3. 所创建的变更日志文件名称为 Release0003.sql
  4. 数据库的 URL
  5. 用户名和密码

关于以上URL的value值,下面简单说一下:

Mysql:jdbc:mysql://localhost/liquibase localhost改成实际的数据库URL,liquibase改成实际数据库的名称。

Oracle:jdbc:oracle:thin:@localhost:1521:liquibase localhost:1521改成实际的数据库URL,1521表示数据库的端口号,liquibase改成实际数据库的SID。

数据库的回滚操作

在上述的变更日志和变更集中我们注意到每个变更集后面都加了一个--rollback注释,后面的SQL表示当执行回滚命令时,需要执行的SQL语句。对于我们确定以后不会撤销的操作,变更日志文件中的changeset后面页可以不用定义rollback,也就是说我们可以在需要执行rollback的时候再添加相应changeset的rollback,不影响我们部署SQL,只是当我们部署SQL时候要根据rollback的方便性来格式化SQL语句。

假如我们想撤销对于Release0003.sql的操作,我们就可以使用rollback了。

执行命令

liquibase --changeLogFile=./Release0003.sql --driver=com.mysql.jdbc.Driver --classpath=./mysql-connector-java-5.1.10-bin.jar --url="jdbc:mysql://localhost/liquibase?useUnicode=true&characterEncoding=UTF-8" --username=test --password=123456  rollbackToDate 2013-07-16T16:55:37

3. 常用的标签及命令

一个<changeSet>标签对应一个变更集,由属性idname,以及changelog的文件路径唯一标识。changelog在执行的时候并不是按照id的顺序,而是按照changeSet在changelog中出现的顺序。

LiquiBase在执行changelog时,会在数据库中插入两张表:DATABASECHANGELOGDATABASECHANGELOGLOCK,分别记录changelog的执行日志和锁日志。

LiquiBase在执行changelog中的changeSet时,会首先查看DATABASECHANGELOG表,如果已经执行过,则会跳过(除非changeSet的runAlways属性为true,后面会介绍),如果没有执行过,则执行并记录changelog日志;

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 table, rename 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

示例文件已放在github上,有兴趣的童鞋可以参考下。

给我留言

留言无头像?


×
腾讯微博