Liquibase

Liquibase使い方(基本)メモ

More than 3 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 が同期できているかをチェックできる。


参考