web-dev-qa-db-ja.com

既存のSpring Bootプロジェクトにリキベースを追加する正しい方法

私は既存のSpring Bootプロジェクトとそのためのデータベースを持っています。ここで、データベースの移行をさらに処理するためにliquibaseを追加したいと思います。これを行うための正しい手順は何ですか?

私は この記事 に従ってリキベースを追加し、変更ログを生成しました。私が見つけたほとんどの記事は、プロジェクトで最初からliquibaseを使用することについて話しているか、実装についてあまり詳細ではありません。これまでのところ、私は次のことを行いました:

Pom.xmlに依存関係とプラグインを追加しました

<dependencies>
    //..other dependencies
    <dependency>
        <groupId>org.liquibase</groupId>
        <artifactId>liquibase-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.liquibase</groupId>
        <artifactId>liquibase-maven-plugin</artifactId>
        <version>3.6.2</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-maven-plugin</artifactId>
            <version>3.6.2</version>
            <configuration>
                <propertyFile>src/main/resources/liquibase.properties</propertyFile>
            </configuration>
        </plugin>
    </plugins>
</build>

Src/main/resourcesの下にliquibase.propertiesファイルを追加しました

url=jdbc:mysql://localhost:3306/demodb
username=root
password=root
driver=com.mysql.jdbc.Driver
outputChangeLogFile=src/main/resources/db/changelog/changes/demodb-changelog.xml

変更ログを処理するためにsrc/main/resourcesの下のapplication.propertiesファイルを更新

#Hibernate
spring.datasource.url=jdbc:mysql://localhost:3306/demodb
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root

#Jpa
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

#Liquibase
spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.xml

Src/main/resources/db/changelogの下にdb.changelog-master.xmlファイルを作成しました

<?xml version="1.0" encoding="UTF-8"?>

<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.9" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation = "http://www.liquibase.org/xml/ns/dbchangelog/1.9
        http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.9.xsd">

</databaseChangeLog>

Spring Bootアプリを実行して、データベースにDATABASECHANGELOG(現時点では空)とDATABASECHANGELOGLOCK(現時点では単一のnullエントリがある)の2つの新しいテーブルを作成します。

ターミナルからdemodb-changelog.xmlファイルを生成して、データベースの現在の状態の変更ログを作成しました

mvn liquibase:generateChangeLog

次に、現在の変更ログを実行時に同期するために、liquibase.propertiesに追加しました:

changeLogFile=src/main/resources/db/changelog/changes/demodb-changelog.xml

そして、ターミナルから実行しました:

mvn liquibase:changelogSync

これで、DATABASECHANGELOGテーブルには、実行された変更ログのエントリが含まれます。

次にdb.changelog-master.xmlファイルに、生成されたファイルを追加します。

<include file="db/changelog/changes/demodb-changelog.xml"/>

ここで、アプリを実行すると、例外が発生します。

Caused by: liquibase.exception.MigrationFailedException: 
Migration failed for change set db/changelog/changes/demodb-changelog.xml
Reason: liquibase.exception.DatabaseException: Table 'abc' already exists

したがって、これは変更ログファイルを再度実行しようとしています。まだ実行されていないチェンジセットのみを実行するように構成するにはどうすればよいですか? DATABASECHANGELOGの機能は、実行されたチェンジセットを処理することであると思いましたが、私はここで間違っていると思います。

db.changelog-master.xmlincludeタグなしでアプリケーションを実行することもできますが、このアプリケーションをデータベース全体を最初から作成する別のマシン。

では、まだ実行されていない変更ログのみを実行するようにliquibaseを構成するにはどうすればよいですか?

3

MySQLはliquibaseのログをテーブルに保持します。

LiquibaseはDATABASECHANGELOGテーブルを使用して、実行されたchangeSetを追跡します。

変更ログが実行されるたびに、変更ログごとに1つの行がテーブルに追加されます。IDに基づいて、実行された変更ログを確認できます。

runAlwaysrunOnChangeのようないくつかのフラグがあり、これらは実行する/実行しないのに役立ちます。

あなたは参照することができます:

For understanding flags:

https://www.liquibase.org/documentation/changeset.html

For understanding DATABASECHANGELOG Table: 

https://www.liquibase.org/documentation/databasechangelog_table.html

2
Maharjun M

ここでの問題は、filenameテーブルに格納されているDATABASECHANGELOGフィールドです。

Liquibaseは、changeSetだけでなく、ididだけでなく、authorのIDを判別しますが、代わりに、3つのフィールドすべての値に基づいて、changeSetのIDを判別します:idauthorfilename

mvn liquibase:updateまたはmvn liquibase:changelogSyncを実行すると、変更ログのfilenamesrc/main/resources/db/changelog/changes/demodb-changelog.xmlになります。これは、liquibaseによって各テーブル行のDATABASECHANGELOG.FILENAMEフィールドに格納される値です。

ただし、Spring-Bootアプリケーションを起動すると、変更ログのファイル名はclasspath:db/changelog/db.changelog-master.xmlであり、変更ログに含まれるファイルの名前はdb/changelog/changes/demodb-changelog.xmlです。

次に、Liquibaseは、どのチェンジセットがすでに適用されているかをチェックします。

idテーブルの各チェンジセットとdb/changelog/changes/demodb-changelog.xmlファイルの各チェンジセットのauthorfilenameDATABASECHANGELOGをチェックしましたが、filenameフィールドが異なるため、何も一致しませんでした。 DBでは、その値はsrc/main/resources/db/changelog/changes/demodb-changelog.xmlです。

src/main/resources/db/changelog/changes/demodb-changelog.xml != db/changelog/changes/demodb-changelog.xml

したがって、Liquibaseはこれらが異なるチェンジセットであると考え、それらを適用しようとします。テーブルが既に存在するため失敗します。しかし、変更セットを複数回適用できるものに変更すると、Liqibaseは、DATABASECHANGELOGテーブルの同じid、同じauthor、ただしfilenameが異なる行の新しいセットを作成したことがわかります。

正直なところ、私はこの問題を解決する方法を知りません。 Spring BootのLiquibaseがどのように機能するかという根本的な問題のようです。スプリングブートアプリケーションの起動時に変更ログファイルを読み取る場合、特にデフォルトの脂肪の場合、それらは[〜#〜] [〜#〜]でなければなりません-jarを使用。しかし、Liquibaseをmavenプラグインとして実行すると、 彼らは通常ローカルファイルシステムにあります (それは真実ではありません。私の「アップデート2」を参照してください)。

いくつかの回避策が存在する可能性があります。コメントに追加してください。回答を更新します。

更新

私が見つけた1つの回避策は、 <databaseChangeLog> タグのlogicalFilePath属性を使用することです。

変更セットの一意の識別子を作成するときに、ファイル名とパスを上書きするために使用します。変更ログを移動または名前変更するときに必要です。

すべての変更ログ/変更セットに注意深く設定すれば、機能するはずです。

db/changelog/changes/demodb-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"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
      http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd"
        logicalFilePath="db/changelog/changes/demodb-changelog.xml">

</databaseChangeLog>

ただし、<include>タグには注意してください。未加工の*.sqlファイルを含めることができます。また、それらにlogicalFilePathを設定することはできません。また、<databaseChangeLog>タグに設定されているlogicalFilePathも継承されません。

更新2

より堅牢なソリューションを見つけました。

MavenプラグインのchangeLogFileプロパティでプレフィックスsrc/main/resourcesを指定しないでください。このようにして、mavenはファイルシステムではなくクラスパスで変更ログを検索します。したがって、liquibase mavenプラグインを実行する前に、まずmvn process-resourcesを実行する必要があります。

したがって、liquibase mavenプラグイン(liquibase.propertiesファイル)のchangeLogFileプロパティは次のようになります。

changeLogFile=db/changelog/changes/demodb-changelog.xml

次に、実行すると

mvn process-resources liquibase:changelogSync

LiquibaseはDATABASECHANGELOGテーブルにレコードを作成します。FILENAMEフィールドはdb/changelog/changes/demodb-changelog.xmlに等しく、これはファイル名と同じで、起動時にマイグレーションを実行するときにspring-bootによって使用されます(classpath:プレフィックスは、ファイル名を比較するときにLiquibaseによって自動的に取り除かれます)。そして最後に、これによりLiquibaseは、これらが同じチェンジセットのセットであり、すでに適用されていることを理解するようになります。

1