私は既存の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.xml
のinclude
タグなしでアプリケーションを実行することもできますが、このアプリケーションをデータベース全体を最初から作成する別のマシン。
では、まだ実行されていない変更ログのみを実行するようにliquibaseを構成するにはどうすればよいですか?
MySQLはliquibaseのログをテーブルに保持します。
LiquibaseはDATABASECHANGELOGテーブルを使用して、実行されたchangeSetを追跡します。
変更ログが実行されるたびに、変更ログごとに1つの行がテーブルに追加されます。IDに基づいて、実行された変更ログを確認できます。
runAlways
、runOnChange
のようないくつかのフラグがあり、これらは実行する/実行しないのに役立ちます。
あなたは参照することができます:
For understanding flags:
https://www.liquibase.org/documentation/changeset.html
For understanding DATABASECHANGELOG Table:
https://www.liquibase.org/documentation/databasechangelog_table.html
ここでの問題は、filename
テーブルに格納されているDATABASECHANGELOG
フィールドです。
Liquibaseは、changeSet
だけでなく、id
とid
だけでなく、author
のIDを判別しますが、代わりに、3つのフィールドすべての値に基づいて、changeSet
のIDを判別します:id
、author
、filename
。
mvn liquibase:update
またはmvn liquibase:changelogSync
を実行すると、変更ログのfilename
はsrc/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
ファイルの各チェンジセットのauthor
、filename
、DATABASECHANGELOG
をチェックしましたが、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は、これらが同じチェンジセットのセットであり、すでに適用されていることを理解するようになります。