当前位置: 首页 > 知识库问答 >
问题:

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

江鸿羲
2023-03-14

我有一个现有的spring boot项目和一个数据库。现在,我想添加liquibase来处理进一步的数据库迁移。做这件事的正确步骤是什么?

我已经跟随本文添加liquibase并生成Changelog。我发现的大多数文章都在讨论从零开始在项目中使用liquibase,或者对实现并不太详细。到目前为止,我已经完成了以下工作:

<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下添加了

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文件以处理changelogs

#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>
mvn liquibase:generateChangeLog

然后,为了同步执行的当前changelogs,在LiquiBase.properties中添加:

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

然后从终点站跑出来:

mvn liquibase:changelogSync

现在,DatabaseChangelog表包含了执行的changelogs的条目。

<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

我可以在db.changelog-master.xml中不使用include标记来运行应用程序,但是我想所有的changelog文件都需要在这里列出,因为如果我要在另一台机器上运行这个应用程序来从头创建整个数据库,就需要所有的changelog文件。

那么如何配置liquibase只运行尚未执行的changelogs呢?

共有1个答案

寇升
2023-03-14

这里的问题是databaseChangelog表中存储的filename字段。

Liquibase不仅通过IDIDauthor确定变更集的标识,而是根据以下三个字段的值确定变更集的标识:IDauthorfilename

当您运行MVN LiquiBase:updateMVN LiquiBase:ChangelogSync时,changelog的文件名src/main/resources/db/changelog/changes/demodb-changelog.xml。这是由liquibase存储到每个表行的databaseChangelog.filename字段中的值。

但是,当您启动spring-boot应用程序时,changelog的文件名是类路径:db/changelog/db.changelog-master.xml,changelog的文件名是db/changelog/changes/demodb-changelog.xml

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

它检查databaseChangelog表中每个变更集的IDauthorfilename文件名以及db/changelog/changes/demodb-changelog.xml文件中的每个变更集,发现没有任何匹配,因为filename字段不同。在数据库中,它的值是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如何工作的一个基本问题。在spring-boot应用程序start上读取changelog文件时,它们必须在类路径中,尤其是在使用默认fat-jar的情况下。但是当您将Liquibase作为maven插件运行时, 它们通常在本地文件系统(这不是真的,请参阅我的“更新2”)。

也许有一些解决办法存在,请在评论中添加它,我会更新答案。

更新

如果您在所有的ChangeLogs/ChangeSet中仔细地设置它,它应该可以工作。

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>

但是要注意 标记。它支持包含原始*.sql文件。并且不能为它们设置LogicalFilePath。在 标记上设置的LogicalFilePath也不继承。

只是不要在maven插件的ChangelogFile属性中指定前缀src/main/resources。这样,maven将在类路径中搜索changelog,而不是在文件系统中。因此,在执行liquibase maven插件之前,必须首先执行MVN process-resources

因此,liquibase maven插件的ChangelogFile属性(liquibase.properties文件)应该如下所示:

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

然后,当你跑的时候

mvn process-resources liquibase:changelogSync

Liquibase将在databaseChangelog表中创建记录,其中filename字段等于db/changelog/changes/demodb-changelog.xml,该字段等于filename,由spring-boot在启动时运行迁移时使用(classpath:前缀由Liquibase在比较文件名时自动删除)。最后,这让Liquibase明白,这些都是相同的变更集,它们已经被应用了。

 类似资料:
  • 问题内容: 在IntelliJ IDEA中创建新的Java项目时,将创建以下目录和文件: 我想配置IntelliJ IDEA,以将我的依赖项JAR包含到项目中。在IntelliJ IDEA中实现此目标的正确方法是什么? 问题答案: 在IntelliJ IDEA中添加外部jar的步骤: Click File from the toolbar Project Structure (CTRL + SHI

  • 问题内容: 如何在Eclipse中将现有的Java项目添加到git中? 我注意到在创建项目时,有一个选项可以添加到源代码管理中,但是对于现有项目,我找不到此选项。这是可以从Eclipse中的git插件实现的,还是必须从命令行完成?(我使用的是Mac) 问题答案: 另一种方法(我发现内置的Eclipse工具有时很挑剔): 打开您的终端 导航到您的项目目录 键入以创建存储库 假设该文件夹中已经有文件,

  • 如何在这个现有项目中使用Maven? 此外,当我尝试添加Maven Project并在步骤“Select a Archetype”时,所有显示的原型都有版本“Release”。当我在这一步中单击Next时,Eclipse变得没有响应。它使用内存甚至没有增加。

  • 从这篇文章(向IntelliJ项目添加Gradle支持的最佳方式)中,我可以看到我需要做的是“在项目的根目录中添加build.Gradle” 我希望有人能解释一下我是怎么用intelliJ做的?(一直在搜索和阅读——仍然困惑不解)。 我理解一个根目录文件夹是所有项目源的父文件夹,但在intelliJ的标准JavaFX项目中,它是什么/我如何找到它/分配它,然后我如何添加build.gradle?

  • 作为uni项目的一部分,我试图使用JavaFX向现有的Java项目添加图形用户界面。最初的项目使用Java11,我的JavaFX版本是17.0.2,但我只是不断得到很多不同的错误,这取决于我做什么。我在用IntelliJ的创意 有人知道如何将JavaFX添加到现有项目中吗? 我的讲师一点帮助都没有

  • 我对Clojure开发非常陌生,我正在尝试在emacs中处理一些现有的项目。问题是,他们都没有project.clj文件,我也找不到合适的repl。当我,我得到一个工作的repl,但当我试图运行任何命令我得到一个错误说。有关于如何使一个Clojure maven项目与lein repl一起工作的资源吗? 谢谢 编辑:另外,我正在处理的项目是一个嵌套的项目,其中包含多个子项目和它们自己的pom。xm