Help us understand the problem. What is going on with this article?

Liquibase使い方(基本)メモ

More than 5 years have passed since last update.

DBリファクタリングツール「LiquiBase」の基本的な使い方をひとめぐり。

環境

OS

Windows7 64bit SP1

Java

1.7.0_55

データベース

MySQL

Ver 14.14 Distrib 5.5.28, for Win64 (x86)

Oracle

11.2.0.1.0

LiquiBase とは?

  • DB をバージョン管理してしまうツール。
  • DB へのパッチ当てや、マイグレーションなど色々利用できる。
  • DB への変更を XML ファイル(ChangeLog)で管理する。
  • 異なる DB 製品であっても、同じ XML ファイルで変更を反映することができる。
    • シーケンスオブジェクトなど、特定の DB 製品でしかサポートされていないオブジェクトの作成も可能。
  • タグ付けなどを行って、任意の状態に DB を ロールバック したりできる。

ひとめぐり

インストール

こちら から、バイナリをダウンロードする。

今回は、 liquibase-3.0.8-bin.zip をダウンロードした(2014/06/24 現在最新の 3.2.0 にはデグレがあって、タグの生成でぬるぽが発生する)。

ダウンロードした zip を解凍したフォルダにパスを通す。

以下のコマンドを実行して、インストールが完了したことを確認する。

>liquibase --version
Liquibase Version: 3.0.8

Changelog ファイルを作成する

sample.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.1.xsd">

  <changeSet id="1" author="opengl-8080">
    <createTable tableName="TEST_TABLE">
      <column name="ID" type="int">
        <constraints primaryKey="true" nullable="false"/>
      </column>
      <column name="CODE" type="varchar2(8)">
        <constraints nullable="false"/>
      </column>
      <column name="VALUE" type="varchar2(8)">
        <constraints nullable="false"/>
      </column>
    </createTable>
  </changeSet>
</databaseChangeLog>

実行する

>liquibase --driver=com.mysql.jdbc.Driver --classpath=.\mysql-connector-java-5.1.22-bin.jar --changeLogFile=sample.xml --url="jdbc:mysql://localhost/test" --username=test --password=test update
Liquibase Update Successful

>liquibase --driver=oracle.jdbc.driver.OracleDriver --classpath=.\ojdbc6.jar --changeLogFile=sample.xml --url="jdbc:oracle:thin:@localhost:1521:test" --username=test --password=test update
Liquibase Update Successful

確認する

>mysql -u test -ptest test

mysql> show tables;

+-----------------------+
| Tables_in_test        |
+-----------------------+
| databasechangelog     |
| databasechangeloglock |
| test_table            |
+-----------------------+
3 rows in set (0.00 sec)

mysql> desc test_table;
+-------+------------+------+-----+---------+-------+
| Field | Type       | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| ID    | int(11)    | NO   | PRI | NULL    |       |
| CODE  | varchar(8) | NO   |     | NULL    |       |
| VALUE | varchar(8) | NO   |     | NULL    |       |
+-------+------------+------+-----+---------+-------+
3 rows in set (0.02 sec)
>sqlplus test/test@test

SQL> select table_name from user_tables;

TABLE_NAME
------------------------------
DATABASECHANGELOGLOCK
DATABASECHANGELOG
TEST_TABLE

SQL> desc test_table;
 名前                                      NULL?    型
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER(10)
 CODE                                      NOT NULL VARCHAR2(8)
 VALUE                                     NOT NULL VARCHAR2(8)

SQL> SELECT CONSTRAINT_NAME, CONSTRAINT_TYPE FROM USER_CONSTRAINTS WHERE TABLE_NAME='TEST_TABLE' AND CONSTRAINT_TYPE='P';

CONSTRAINT_NAME                C
------------------------------ -
PK_TEST_TABLE                  P

ここまでの説明

  • ChangeLog という XML ファイルに、「テーブル作成」「データの挿入・変更」「テーブル定義の変更」などを記述する。
    • ChangeLog ファイルを指定して liquibase を実行することで、定義した変更をデータベースに反映できる。
    • ChangeLog ファイルには、 changeSet を1つの単位として変更を定義する。
    • changeSet は1トランザクションで実行される。
  • データベースには liquibase が使用するテーブルが自動で作成される(DATABASECHANGELOGDATABASECHANGELOGLOCK)。
    • DATABASECHANGELOG には、適用した changeSet の履歴が保存され、一度適用した changeSet が繰り返し実行されないようになっている。
    • DATABASECHANGELOG には記録されていない、新しい changeSet だけが適用される。

データを登録する

sample.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.1.xsd">

  <changeSet id="1" author="opengl-8080">
    <createTable tableName="TEST_TABLE">
      <column name="ID" type="int">
        <constraints primaryKey="true" nullable="false"/>
      </column>
      <column name="CODE" type="varchar2(8)">
        <constraints nullable="false"/>
      </column>
      <column name="VALUE" type="varchar2(8)">
        <constraints nullable="false"/>
      </column>
    </createTable>
  </changeSet>

  <changeSet id="2" author="opengl-8080">
    <insert tableName="TEST_TABLE">
      <column name="ID" value="1" />
      <column name="CODE" value="hoge" />
      <column name="VALUE" value="HOGE" />
    </insert>
  </changeSet>
</databaseChangeLog>

先ほどと同じ方法で liquibase を実行する。

oracle
SQL> select * from test_Table;

        ID CODE     VALUE
---------- -------- --------
         1 hoge     HOGE
mysql
mysql> select * from test_table;
+----+------+-------+
| ID | CODE | VALUE |
+----+------+-------+
|  1 | hoge | HOGE  |
+----+------+-------+
1 row in set (0.00 sec)

データが登録されている。

毎回入力するオプションをプロパティファイルにまとめる

liquibase.properties
driver=oracle.jdbc.driver.OracleDriver
changeLogFile=sample.xml
classpath=.\\ojdbc6.jar
url=jdbc:oracle:thin:@localhost:1521:test
username=test
password=test
  • driver などを毎回コマンドのオプションに設定するのは面倒なので、カレントフォルダに liquibase.properties を作成し、そこに設定を記載する。
  • バックスラッシュは二重にする。
  • url のダブルクォーテーションは不要なので取り除く。

これで以下のコマンドで実行できるようになる。

>liquibase update

タグを設定してロールバックする

タグを設定する

>liquibase tag hoge
Successfully tagged TEST@jdbc:oracle:thin:@localhost:1521:test
Liquibase 'tag' Successful

ChangeLog を更新して DB に反映させる

sample.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.1.xsd">

  <changeSet id="1" author="opengl-8080">
    <createTable tableName="TEST_TABLE">
      <column name="ID" type="int">
        <constraints primaryKey="true" nullable="false"/>
      </column>
      <column name="CODE" type="varchar2(8)">
        <constraints nullable="false"/>
      </column>
      <column name="VALUE" type="varchar2(8)">
        <constraints nullable="false"/>
      </column>
    </createTable>
  </changeSet>

  <changeSet id="2" author="opengl-8080">
    <insert tableName="TEST_TABLE">
      <column name="ID" value="1" />
      <column name="CODE" value="hoge" />
      <column name="VALUE" value="HOGE" />
    </insert>
  </changeSet>

  <changeSet id="3" author="opengl-8080">
    <addColumn tableName="TEST_TABLE">
      <column name="MEMO" type="varchar2(16)" />
    </addColumn>
  </changeSet>

</databaseChangeLog>
>liquibase update
Liquibase Update Successful
確認
>sqlplus test/test@test

SQL> desc test_table;
 名前                                      NULL?    型
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER(10)
 CODE                                      NOT NULL VARCHAR2(8)
 VALUE                                     NOT NULL VARCHAR2(8)
 MEMO                                               VARCHAR2(16)

SQL> quit

>mysql -u test -ptest test

mysql> desc test_table;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| ID    | int(11)     | NO   | PRI | NULL    |       |
| CODE  | varchar(8)  | NO   |     | NULL    |       |
| VALUE | varchar(8)  | NO   |     | NULL    |       |
| MEMO  | varchar(16) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

タグを設定したところまでロールバックする

>liquibase rollback hoge
Liquibase Rollback Successful
確認
>sqlplus test/test@test

SQL> desc test_table;
 名前                                      NULL?    型
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER(10)
 CODE                                      NOT NULL VARCHAR2(8)
 VALUE                                     NOT NULL VARCHAR2(8)

SQL> quit

>mysql -u test -ptest test

mysql> desc test_table;
+-------+------------+------+-----+---------+-------+
| Field | Type       | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| ID    | int(11)    | NO   | PRI | NULL    |       |
| CODE  | varchar(8) | NO   |     | NULL    |       |
| VALUE | varchar(8) | NO   |     | NULL    |       |
+-------+------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
  • liquibase tag <タグ名> で現在の状態でしるし(タグ)を付けることができる。
  • liquibase rollback <タグ名> で、指定したタグまで DB の状態を戻すことができる。

異なる DB 間の差分を取る

liquibase.properties
driver=oracle.jdbc.driver.OracleDriver
changeLogFile=sample.xml
classpath=.\\ojdbc6.jar
url=jdbc:oracle:thin:@localhost:1521:test
username=test
password=test
referenceUrl=jdbc:oracle:thin:@localhost:1521:test
referenceUsername=test2
referencePassword=test2
>liquibase diff


Diff Results:
Reference Database: TEST2 @ jdbc:oracle:thin:@localhost:1521:test (Default Schema: TEST2)
Comparison Database: TEST @ jdbc:oracle:thin:@localhost:1521:test (Default Schema: TEST)
Product Name: EQUAL
Product Version: EQUAL
Missing Catalog(s):
     TEST2
Unexpected Catalog(s):
     TEST
Changed Catalog(s): NONE
Missing Column(s):
     HOGE.ID
     TEST_TABLE.MEMO
Unexpected Column(s): NONE
Changed Column(s): NONE
Missing Foreign Key(s): NONE
Unexpected Foreign Key(s): NONE
Changed Foreign Key(s): NONE
Missing Index(s): NONE
Unexpected Index(s): NONE
Changed Index(s): NONE
Missing Primary Key(s): NONE
Unexpected Primary Key(s): NONE
Changed Primary Key(s): NONE
Missing Schema(s): NONE
Unexpected Schema(s): NONE
Changed Schema(s): NONE
Missing Sequence(s): NONE
Unexpected Sequence(s):
     TEST_TABLE_SEQ
Changed Sequence(s): NONE
Missing Table(s):
     HOGE
Unexpected Table(s): NONE
Changed Table(s): NONE
Missing Unique Constraint(s): NONE
Unexpected Unique Constraint(s): NONE
Changed Unique Constraint(s): NONE
Missing View(s): NONE
Unexpected View(s): NONE
Changed View(s): NONE
Liquibase 'diff' Successful
  • 比較する DB の設定を reference** で追加して diff コマンドを実行すると、 DB 間の差分を取ることができる。

差分を ChangeLog 形式で出力する

>liquibase diffChangeLog
Liquibase 'diffChangeLog' Successful
sample.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.1.xsd">

  <changeSet id="1" author="opengl-8080">
    <createTable tableName="TEST_TABLE">
      <column name="ID" type="int">
        <constraints primaryKey="true" nullable="false"/>
      </column>
      <column name="CODE" type="varchar2(8)">
        <constraints nullable="false"/>
      </column>
      <column name="VALUE" type="varchar2(8)">
        <constraints nullable="false"/>
      </column>
    </createTable>
  </changeSet>

  <changeSet id="2" author="opengl-8080">
    <insert tableName="TEST_TABLE">
      <column name="ID" value="1" />
      <column name="CODE" value="hoge" />
      <column name="VALUE" value="HOGE" />
    </insert>
  </changeSet>

  <changeSet id="3" author="opengl-8080">
    <addColumn tableName="TEST_TABLE">
      <column name="MEMO" type="varchar2(16)" />
    </addColumn>
  </changeSet>

    <changeSet author="xxx (generated)" id="1403615872792-1">
        <createTable tableName="HOGE">
            <column name="ID" type="NUMBER(38)"/>
        </createTable>
    </changeSet>
    <changeSet author="xxx (generated)" id="1403615872792-2">
        <addColumn tableName="TEST_TABLE">
            <column name="MEMO" type="VARCHAR(16)"/>
        </addColumn>
    </changeSet>
    <changeSet author="xxx (generated)" id="1403615872792-3">
        <dropSequence sequenceName="TEST_TABLE_SEQ"/>
    </changeSet>
</databaseChangeLog>
  • diffChangeLog コマンドを実行すると、差分を ChangeLog に追記させることができる。

データベースの状態を Javadoc 風の HTML で出力する

>liquibase dbDoc docs
Liquibase 'dbDoc' Successful

>dir /b docs
authors
authors.html
changelogs
changelogs.html
columns
currenttables.html
globalnav.html
index.html
overview-summary.html
pending
recent
stylesheet.css
tables

liquibase.JPG

  • liquibase dbDoc <出力先フォルダ> で DB の状態を Javadoc 風の HTML で出力できる。
  • 各テーブルのカラム定義や、どこまで ChangeLog が適用されているかなどが確認できる。

既存の DB から ChangeLog を生成する

liquibase.properties
driver=oracle.jdbc.driver.OracleDriver
changeLogFile=generate.xml
classpath=.\\ojdbc6.jar
url=jdbc:oracle:thin:@localhost:1521:test
username=test
password=test
>liquibase generateChangeLog
Liquibase 'generateChangeLog' Successful

生成が成功すると、 liquibase.properties で指定していた changeLogFile=generate.xml が出力される。

generate.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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.0.xsd">
    <changeSet author="xxx (generated)" id="1403616998655-1">
        <createSequence sequenceName="TEST_TABLE_SEQ"/>
    </changeSet>
    <changeSet author="xxx (generated)" id="1403616998655-2">
        <createTable tableName="TEST_TABLE">
            <column name="ID" type="NUMBER(10, 0)">
                <constraints nullable="false"/>
            </column>
            <column name="CODE" type="VARCHAR2(8)">
                <constraints nullable="false"/>
            </column>
            <column name="VALUE" type="VARCHAR2(8)">
                <constraints nullable="false"/>
            </column>
        </createTable>
    </changeSet>
    <changeSet author="xxx (generated)" id="1403616998655-3">
        <addPrimaryKey columnNames="ID" constraintName="PK_TEST_TABLE" tableName="TEST_TABLE"/>
    </changeSet>
</databaseChangeLog>
  • generateChangeLog で、既存の DB の状態を ChangeLog ファイルで出力できる。
  • これなら、 Liquibase を適用していない既存の DB でも途中から Liquibase を使い始められる? wktk
  • ただし、現状以下のオブジェクトは出力できない。
    • ストアドプロシージャ
    • ファンクション
    • パッケージ
    • トリガー

DB に反映されていない ChangeSet を確認する

>liquibase status --verbose
1 change sets have not been applied to TEST@jdbc:oracle:thin:@localhost:1521:test
     sample.xml::3::opengl-8080
Liquibase 'status' Successful
  • liquibase status --verbose で、まだ DB に反映されていない ChangeSet が分かる。

DB に適用されているのに ChangeLog に記載されていない変な ChangeSet が無いか確認する

sample.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.1.xsd">

  <changeSet id="1" author="opengl-8080">
    <createTable tableName="TEST_TABLE">
      <column name="ID" type="int">
        <constraints primaryKey="true" nullable="false"/>
      </column>
      <column name="CODE" type="varchar2(8)">
        <constraints nullable="false"/>
      </column>
      <column name="VALUE" type="varchar2(8)">
        <constraints nullable="false"/>
      </column>
    </createTable>
  </changeSet>

  <changeSet id="2" author="opengl-8080">
    <insert tableName="TEST_TABLE">
      <column name="ID" value="1" />
      <column name="CODE" value="hoge" />
      <column name="VALUE" value="HOGE" />
    </insert>
  </changeSet>

  <changeSet id="3" author="opengl-8080">
    <addColumn tableName="TEST_TABLE">
      <column name="MEMO" type="varchar2(16)" />
    </addColumn>
  </changeSet>

</databaseChangeLog>
>liquibase unexpectedChangeSets --verbose
1 unexpected changes were found in TEST@jdbc:oracle:thin:@localhost:1521:test
     sample.xml::4::opengl-8080
Liquibase 'unexpectedChangeSets' Successful
  • DB には、 sample.xml の ID=4, author=opengl-8080 という ChangeSet が適用されたという記録が残っている。
  • しかし、実際の sample.xml にはそんな ChangeSet は無い。
  • つまり、 sample.xml が最新になっていない、もしくは誤って ChangeSet を消してしまったような状態。
  • これをチェックするには、 liquibase unexpectedChangeSets --verbose を実行する。
  • 前述の liquibase status と合わせることで、 DB と ChangeLog が同期できているかをチェックできる。

参考

opengl-8080
ただのSE。Java好き。
tis
創業40年超のSIerです。
https://www.tis.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした