Spring Bootでliquibaseを使う方法(MySQL)

Spring Bootでliquibaseを使う方法(MySQL)

Springバージョン
2.1.1.RELEASE

liquibase(リキベース)を使うとSpring Bootアプリケーションを実行する際にデータベースを作成して、さらにテーブルを作成したりデータ投入したり、テーブル削除したりと、マイグレーション管理ができるようです。

とりあえずデータベース作成して、テーブルをcreateしたかったのでliquibaseを使ってみました。

Spring Bootのスタータープロジェクトからliquibaseを選択します。

Spring Bootでliquibaseを使う方法(MySQL)

テーブルを作成するにはxml形式かyml形式でファイルを作成します。Spring Bootアプリケーション起動時に順次読み込んでテーブルを作成していってくれます。

前提として、ローカルPCにMySQLがインストールされていることとします。

build.gradleを以下のように修正します。これで起動時にliquibaseが実行されます。

buildscript {
  ext {
    springBootVersion = '2.1.1.RELEASE'
  }
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
  }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
  mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.liquibase:liquibase-core' // 追加
    runtimeOnly 'mysql:mysql-connector-java'
    compileOnly 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

公式サイトを見るとどうもデフォルトのファイル名はdb.changelog-master.yamlのようです。

src\main\resources\db\db.changelog-master.yamlを配置します。

db.changelog-master.yaml

databaseChangeLog:
- include:
    file: a.yaml

複数ある場合は改行してファイル名を指定していきます。

複数ファイルある場合のdb.changelog-master.yaml(デフォルトのファイル名です)の中身は以下のようになると思います。

databaseChangeLog:
- include:
    file: a.yaml
- include:
    file: b.yaml

上記ではa.yamlを読み込んだ後にb.yamlを読み込みます。

db.changelog-master.yamlでテーブル作成したりもできますし、上記のようにファイル分割することもできます。

a.yamlの記述例です。

databaseChangeLog:
  - changeSet:
      id: 1
      author: confrage
      changes:
        - createTable:
            tableName: person
            columns:
              - column:
                  name: id
                  type: int
                  autoIncrement: true
                  constraints:
                    primaryKey: true
                    nullable: false
              - column:
                  name: firstname
                  type: varchar(50)
              - column:
                  name: lastname
                  type: varchar(50)
                  constraints:
                    nullable: false
              - column:
                  name: state
                  type: char(2)

参考サイト

プロパティ名

MySQLにクエリパラメータでプロパティを設定することができます。

createDatabaseIfNotExist=true … データベースが存在しなければデータベースを作成する

参考サイト

application.properties

このファイルにMySQLの接続情報を記載しておきます。

spring.datasource.url=jdbc:mysql://localhost:3306/sampledb?serverTimezone=UTC&createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=system
spring.jpa.database=MYSQL
spring.liquibase.change-log=classpath:db/db.changelog-master.yaml

spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.yamlでクラスパスとファイル名を変更できます。

Spring Bootアプリケーションを実行する

ではSpring Bootアプリケーションを実行してみます。sampledbというデータベースが作成され、databasechangelogテーブル、databasechangeloglockテーブル、personテーブルが作成されればOKです。

mysql> desc person;
+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int(11)     | NO   | PRI | NULL    | auto_increment |
| firstname | varchar(50) | YES  |     | NULL    |                |
| lastname  | varchar(50) | NO   |     | NULL    |                |
| state     | char(2)     | YES  |     | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+
4 rows in set (0.03 sec)

テーブルにカラムを追加する

liquibaseはテーブルを作成しますが、そのあとテーブルのカラムが追加だったりした場合に新たにymlファイルを作成して、既存テーブルに対してALTER TABLE文を発行します。

ALTER TABLE文の実行方法は以下のようにします。

databaseChangeLog:
  - changeSet:
      id:11111112
      comment: IDです
      author: takahashi
      changes: 
        - addColumn:
            catalogName: スキーマ名
            columns:
              - column:
                  name: カラム名
                  remarks: 備考とかメモ
                  type: DATETIME
            schemaName: スキーマ名
            tableName: テーブル名

これで以下を実行するのと同じになります。MySQLではcatalogNameとschemaNameは省略可能です。

ALTER TABLE スキーマ名.テーブル名 ADD カラム名 DATETIME NULL;

カラムを複数追加したい場合は- column:の箇所を追加したい文だけ記述します。

テーブルのカラム名をリネームする

liquibaseはマイグレーションツールですが、簡単に言うとテーブル作成します。で、カラム名変わったのでカラム名を変更します。そのあとにテーブルが不要になったのでdropします、というような履歴ツールです。

今回はカラム名をリネームするymlを作成します。

databaseChangeLog:
  - changeSet:
      id:11111112
      comment: IDです
      author: takahashi
      changes: 
        - renameColumn:
            catalogName: スキーマ名
            columnDataType:VARCHAR(10)
            newColumnName: 新カラム名
            oldColumnName: 旧カラム名
            remarks: 備考とかメモ
        schemaName: public
        tableName: テーブル名

これでカラム名をリネームできるのですが、旧カラム名にnot null制約がついていた場合、制約が消えてしまいます。その場合は以下のように記述する必要があります。

databaseChangeLog:
  - changeSet:
      id:11111112
      comment: IDです
      author: takahashi
      changes: 
      - renameColumn:
          catalogName: スキーマ名
          columnDataType:VARCHAR(10)
          newColumnName: 新カラム名
          oldColumnName: 旧カラム名
          remarks: 備考とかメモ
          schemaName: public
          tableName: テーブル名
      - addNotNullConstraint: 
          catalogName: スキーマ名
          columnDataType: VARCHAR(10) 
          columnName: 新カラム名
          defaultNullValue:
          schemaName: public
          tableName: テーブル名

テーブルのカラムの型を変更する

テーブルのカラムの型を変更するymlを作成します。以下ではintに変更しています。

databaseChangeLog:
  - changeSet:
      id:11111112
      comment: IDです
      author: takahashi
      changes: 
      - modifyDataType:
          catalogName: スキーマ名 
          columnName: 変更対象のカラム名
          newDataType: int
          schemaName: public
          tableName: テーブル名

ユニークキーを付ける

ユニークキーを付けます。

databaseChangeLog:
  - changeSet:
      id:11111112
      comment: IDです
      author: takahashi
      changes: 
       - addUniqueConstraint:
        columnNames: キー1,キー2,キー3
        constraintName: ユニーク制約名
                deferrable: true
        disable: true
        initiallyDeferred: true
        catalogName: スキーマ名
        schemaName: public
        tableName: テーブル名

以下と同様です。

ALTER TABLE テーブル名 ADD CONSTRAINT ユニーク制約名 UNIQUE (xx,yy,zz);

初期データをインサートする

liquibaseはテーブルを作成してくれますが、作成時はレコードがありません。

これは不便なのですが、もちろん初期レコードをインサートすることも可能です。

databaseChangeLog:
  - changeSet:
    id:11111113
    comment: IDです
    author: takahashi
    changes:
    - createTable:
      tableName: sampleTbl
      remarks: サンプルテーブルです
      columns:
      - column:
        name: emp_id
        remarks: 従業員ID
        type: VARCHAR(10)
        constrains:
          nullable: false
      - column:
        name: emp_name
        remarks: 従業員名
        type: VARCHAR(30)
        constrains:
          nullable: false
    - sql:
      sql: INSERT INTO sampleTbl (emp_id, emp_name) VALUES ('1', '高橋')
    - sql:
      sql: INSERT INTO sampleTbl (emp_id, emp_name) VALUES ('2', 'デーミヤン') 

これはテーブルを作成してから2件インサートしている例です。

DATABASECHANGELOGテーブルを触る

DATABASECHANGELOGテーブルは管理テーブルですが、何かの拍子でおかしくなればそのエラーが出ているymlファイルの1レコードだけを削除して、再度実行することができます。

この時、yamlに記載されているのがCREATE TABLEだったら、あらかじめDROP TABLEしておくなどの対応は必要です。

DATABASECHANGELOGLOCKテーブルは触ることはない気がします。

liquibase(MySQL)でパーティショニングする

liquibase(MySQL)でパーティショニングするには、sqlでalter文を使うしか方法がありません。フォーラム

postgreSQLはmodifySqlがサポートされているようです。参考サイト

  modifySql:
    dbms: postgresql
    append value: PARTITION BY RANGE COLUMNS(borned) (PARTITION p0 VALUES LESS THAN ('2000-01-01 00:00:00'),PARTITION p1 VALUES LESS THAN (MAXVALUE));

MySQLでは以下のようにsqlで記述する必要があります。

databaseChangeLog:
  - changeSet:
      id: 1
      author: takahashi
      changes:
        - createTable:
            tableName: person
            columns:
              - column:
                name: id
                type: int
                constraints:
                  nullable: false
              - column:
                name: firstname
                type: varchar(50)
              - column:
                name: lastname
                type: varchar(50)
                constraints:
                  nullable: false
              - column:
                name: borned
                type: datetime
            sql: |
              alter table person
              PARTITION BY RANGE COLUMNS(borned)
              (PARTITION p0 VALUES LESS THAN ('2000-01-01 00:00:00'),
              PARTITION p1 VALUES LESS THAN (MAXVALUE));

コメント

タイトルとURLをコピーしました