Spring boot 将liquibase添加到现有spring引导项目的正确方法

Spring boot 将liquibase添加到现有spring引导项目的正确方法,spring-boot,database-migration,liquibase,Spring Boot,Database Migration,Liquibase,我有一个现有的spring boot项目和一个数据库。现在,我想添加liquibase来处理进一步的数据库迁移。执行此操作的正确步骤是什么 我随后添加了liquibase并生成了changelog。我发现的大多数文章都谈到在项目中从头开始使用liquibase,或者没有太详细地介绍实现。到目前为止,我已经做了以下工作: 在pom.xml中添加了依赖项和插件 <dependencies> //..other dependencies <dependency>

我有一个现有的spring boot项目和一个数据库。现在,我想添加liquibase来处理进一步的数据库迁移。执行此操作的正确步骤是什么

我随后添加了liquibase并生成了changelog。我发现的大多数文章都谈到在项目中从头开始使用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下的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>
然后在
liquibase.properties
added中同步当前已执行的变更日志:

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"/>
因此,这是在尝试再次运行changelog文件。如何配置为仅运行那些尚未运行的变更集?我以为
DATABASECHANGELOG
的功能是处理已执行的变更集,但我猜我错了

我可以在没有
db.changelog master.xml
中的
include
标记的情况下运行该应用程序,但我想这里需要列出所有的changelog文件,因为如果我要在另一台机器上运行该应用程序,从头开始创建整个数据库,我需要所有的changelog文件


那么如何将liquibase配置为只运行尚未执行的变更日志呢?

MySQL将在表中维护liquibase的日志

Liquibase使用DATABASECHANGELOG表跟踪已运行的变更集

无论何时运行变更日志,都会为每个变更日志添加一行表,根据ID,我们可以知道运行了哪些变更日志

有一些标志,如
runAlways
runOnChange
,它们将帮助我们执行/不执行

你可以参考:

For understanding flags:


这里的问题是存储在
数据库更改日志
表中的
文件名
字段

Liquibase不仅通过
id
id
author
来确定
变更集的身份,而是基于所有三个字段的值来确定
变更集的身份:
id
author
filename

运行
mvn liquibase:update
mvn liquibase:changelogSync
时,变更日志的
文件名
src/main/resources/db/changelog/changes/demodab changelog.xml
。这是liquibase存储到每个表行的
DATABASECHANGELOG.FILENAME
字段中的值

但是,当您启动spring boot应用程序时,变更日志的文件名是
classpath:db/changelog/db.changelog master.xml
,其中包含的变更日志的文件名是
db/changelog/changes/demodab changelog.xml

然后,Liquibase检查已经应用了哪些变更集

它检查
DATABASECHANGELOG
表中每个变更集的
id
author
filename
,以及
db/changelog/changes/demodab changelog.xml
文件中的每个变更集,发现没有匹配的内容,因为
filename
字段不同。在DB中,它的值是
src/main/resources/DB/changelog/changes/demodab changelog.xml

src/main/resources/db/changelog/changes/demodb-changelog.xml != db/changelog/changes/demodb-changelog.xml
因此,Liquibase认为这些是不同的变更集,并尝试应用它们。它失败,因为表已经存在。但是,如果您将变更集更改为可以多次应用的内容,您将看到Liqibase为
数据库变更日志
表中的行创建了一个新的变更集,具有相同的
id
,相同的
作者
,但不同的
文件名

老实说,我不知道如何解决这个问题。这看起来像是Spring Boot中Liquibase如何工作的一个基本问题。当在spring启动应用程序启动时读取changelog文件时,它们必须位于类路径中,尤其是在使用默认fat jar的情况下。但当您以maven插件的形式运行Liquibase时,它们通常位于本地文件系统上(这不是真的,请参阅我的“更新2”)

可能存在一些解决方法,请将其添加到评论中,我将更新答案

更新

我发现的一个解决方法是使用标签的
logicalFilePath
属性

用于在创建更改集的唯一标识符时替代文件名和路径。移动或重命名更改日志时需要

如果您在所有变更日志/变更集中仔细地设置它,它应该可以工作

db/changelog/changes/demodab 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>
然后,当你跑的时候

mvn process-resources liquibase:changelogSync

Liquibase将在
DATABASECHANGELOG
表中创建记录,其中
FILENAME
字段等于
db/changelog/changes/demodab changelog.xml
,这等于spring boot在启动时运行迁移时使用的文件名(
classpath:
前缀在比较文件名时由Liquibase自动去除). 最后,这使Liquibase了解到,这些是相同的变更集集集,并且它们已经应用。

在生成变更日志时,是否可以对所有变更集设置runAlways=“false”或runOnChange=“true”?还是应该手动执行此操作?runOnChange为true。有时,您必须根据情况删除表中的行。您是否尝试将生成的文件包含在changelog master中,然后运行changeLogSync?您在Update 2中的解决方案有效,这就是我正在玩的测试项目中的解决方案。然而,有一个有趣的怪癖。只是喝了酒
For understanding DATABASECHANGELOG Table: 
src/main/resources/db/changelog/changes/demodb-changelog.xml != 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>
changeLogFile=db/changelog/changes/demodb-changelog.xml
mvn process-resources liquibase:changelogSync