【问题标题】:How can I configure Maven Liquibase plugin in Spring Boot?如何在 Spring Boot 中配置 Maven Liquibase 插件?
【发布时间】:2019-08-30 23:35:24
【问题描述】:

我正在学习 Liquibase 和 Spring Boot,所以我用Spring Initializr 创建了一个简单的项目。

在我添加的 POM.xml 文件中:

    <plugin>
        <groupId>org.liquibase</groupId>
        <artifactId>liquibase-maven-plugin</artifactId>
        <version>3.4.1</version>
        <configuration>
            <propertyFile>src/main/resources/application.properties</propertyFile>
        </configuration>
    </plugin>

我已将 application.properties 指定为属性文件,因此我的应用程序的所有配置都可以在单个文件中进行。

当我从 IntelliJ 运行任何 liquibase-maven-plugin 任务时,我会收到不同的错误,这是一个运行 changeLogSync 任务的示例:

[ERROR] Failed to execute goal org.liquibase:liquibase-maven-plugin:3.4.1:changelogSync (default-cli) on project simpleTest: The changeLogFile must be specified

如果我在 application.properties 中添加正确的键,我就能让它工作。

例如,我发现 liquibase-maven-plugin 不会读取 spring.datasource.url 属性,但它只会读取 url 属性。

因此,我的 application.properties 必须是类似的:

environment                         = JUnit
spring.datasource.url               = jdbc:h2:file:./target/test
spring.datasource.driver-class-name = org.h2.Driver
spring.datasource.username          = sa
spring.datasource.password          = sa
spring.liquibase.change-log         = classpath:/db/changelog/db.changelog-master.yaml
spring.h2.console.enabled           = true
spring.h2.console.path              = /h2-console


# Keys needed for liquibase maven plugin
url                                 = jdbc:h2:file:./target/test
username                            = sa
password                            = sa

如果我遵循这种模式,我最终会在 application.properties 中拥有几个名称稍有不同但值相同的键,这种解决方案显然非常丑陋且效率低下。

在 Spring Boot 中配置和使用 Liquibase Maven 插件的高效且可维护的方法是什么?

在收到 Amith Kumar 的答复后进行编辑:

environment=JUnit
spring.datasource.url=jdbc:h2:file:./target/glossary-test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=sa
spring.liquibase.change-log=classpath:/db/changelog/db.changelog-master.yaml
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
url=${spring.datasource.url}
changeLogFile=${spring.liquibase.change-log}
username=${spring.datasource.username}
password=${spring.datasource.password}

编辑后出错:

[ERROR] Failed to execute goal org.liquibase:liquibase-maven-plugin:3.4.1:dropAll (default-cli) on project test: Error setting up or running Liquibase: liquibase.exception.DatabaseException: java.lang.RuntimeException: Cannot find database driver: Driver class was not specified and could not be determined from the url (${spring.datasource.url}) -> [Help 1]

【问题讨论】:

    标签: java maven spring-boot liquibase


    【解决方案1】:

    Liquibase maven 插件支持通过 pom.xml 进行配置注入。

    因此,您可以使用properties-maven-plugin 将您的属性包含在 application.properties 中(如果您使用的是 application.yml,则使用 yaml-properties-maven-plugin),然后将它们注入到 liquibase 配置中:

    示例:

    <plugin>
        <groupId>it.ozimov</groupId>
        <artifactId>yaml-properties-maven-plugin</artifactId>
        <version>1.1.3</version>
        <executions>
                        <execution>
                                <phase>initialize</phase>
                                <goals>
                                        <goal>read-project-properties</goal>
                                </goals>
                                <configuration>
                                        <files>
                                                <file>src/main/resources/application.yml</file>
                                        </files>
                                </configuration>
                        </execution>
         </executions>
    </plugin>
    

    现在您可以在 liquibase 配置中注入这些属性:

    <plugin>
                <groupId>org.liquibase</groupId>
                <artifactId>liquibase-maven-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <changeLogFile>src/main/resources/db/changelog/db.changelog-master.yaml</changeLogFile>
                    <driver>${spring.datasource.driverClassName}</driver>
                    <url>${spring.datasource.url}</url>
                    <username>${spring.datasource.username}</username>
                    <password>${spring.datasource.password}</password>
                    <promptOnNonLocalDatabase>false</promptOnNonLocalDatabase>
                    <databaseChangeLogTableName>DATABASECHANGELOG</databaseChangeLogTableName>
                    <databaseChangeLogLockTableName>DATABASECHANGELOGLOCK</databaseChangeLogLockTableName>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>javax.xml.bind</groupId>
                        <artifactId>jaxb-api</artifactId>
                        <version>2.3.0</version>
                    </dependency>
                </dependencies>
    </plugin>
    

    我还需要设置logicalFilePath,以确保spring boot集成推断的changelog路径和maven插件所在的地方一致。

    【讨论】:

      【解决方案2】:

      application.properties 设置可以快速启动并运行应用程序,但在灵活性方面不是最佳解决方案

      我的建议是使用@Configuration 配置数据源,例如here

      然后配置上面定义的liquibase传递数据源如下

      @Configuration
      public class LiquibaseConfigurer {
      
          @Autowired
          @Qualifier("primaryDataSource")
          private DataSource oltpDataSource;
      
          @Bean
          @DependsOn
          public SpringLiquibase liquibase() {
              SpringLiquibase liquibase = new SpringLiquibase();
              liquibase.setChangeLog("classpath:liquibase/liquibase-changelog.xml");
              liquibase.setDataSource(oltpDataSource);
              return liquibase;
          }
      }
      

      在这种情况下你只需要liquibase-core 依赖如下

          <dependency>
              <groupId>org.liquibase</groupId>
              <artifactId>liquibase-core</artifactId>
          </dependency>
      

      一个更简单的替代方法是在应用程序外部配置 liquibase,而不使用 maven 插件。

      下载库,或者使用一些包管理器安装它,然后启动一个包含所有设置的命令行

      liquibase --driver=org.h2.Driver \
           --classpath=/path/to/h2/driver.jar \
           --changeLogFile=/db/changelog/db.changelog-master.yaml \
           --url="jdbc:h2:file:./target/glossary-test" \
           --username=sa \
           --password=sa \
           --logLevel=debug \
           migrate
      

      不管怎样,你现在遇到的问题是因为你写了这个:

      url=${spring.datasource.url}
      

      我不知道您在哪里找到此语法,但尝试复制连接 url 并替换为以下内容

      url=jdbc:h2:file:./target/test
      

      对其他设置执行相同操作

      【讨论】:

      • 我从 Amith 收到的另一个答案中建议了 ${} 符号。虽然我认为这是一个普遍的想法,但在使用 Maven Liquibase 插件时它不起作用。当您在控制台中启动其中一项任务时,它会打印“属性文件中的'spring.datasource.url'未被此任务使用。”。感谢灵活的解决方案和回购链接:)
      • 是的,正是我想说的(占位符在那里不起作用)
      • 您知道,spring boot 开箱即用地为您管理 liquibase。除非您的项目中有多个数据源或者您偏离了 Spring 默认配置,否则您不需要明确需要 DataSourceSpringLiquibase bean。请参考 spring documentation & sample spring git project from pivotal。
      • 我对 hikaricp、url 和数据源也有一些问题。不幸的是,我现在不记得细节了。我一般来说这种设置的“问题”是它们适合非常基本的场景或原型应用程序。
      • 如果我想使用回滚目标,我该怎么做?我认为类方法对于 maven 目标无关紧要,对吧?有差距……
      【解决方案3】:

      这在许多项目中很常见。

      当您使用多个插件/库时,每个插件/库都需要环境配置中的某些属性,其中键名在其本机命名法中定义。

      没有针对此问题的标准化

      为了避免为多个属性提供相同的值,容易出错,建议使用引用。

      # Keys needed for liquibase maven plugin
      url=${spring.datasource.url}
      

      更新

      我注意到您在运行 liquibase maven 插件时遇到了异常,该插件当然是在 spring 上下文之外运行的。我之前提供的解决方案适用于 spring 上下文,即当您启动应用程序时。

      对于给定的场景,使用 maven filter resource files 功能。所以你的命令会变成

      mvn liquibase:generateChangeLog 资源:资源

      您的设置将如下所示:

      src/main/filters/filter.properties

      db.url=jdbc:h2:file:./target/glossary-test
      db.username=sa
      db.password=sa
      db.driver=org.h2.Driver
      db.lb.changeLogFile=classpath:/db/changelog/db.changelog-master.yaml
      

      application.properties

      spring.datasource.url=@db.url@
      spring.datasource.username=@db.username@
      spring.datasource.password=@db.password@
      spring.datasource.driver-class-name=@db.driver@
      url=@db.url@
      username=@db.username@
      password=@db.password@
      driver=@db.driver@
      changeLogFile=@db.lb.changeLogFile@
      

      pom.xml

      <build>
      ......
          <plugins
              ......
              <plugin>
                  <groupId>org.liquibase</groupId>
                  <artifactId>liquibase-maven-plugin</artifactId>
                  <version>3.6.3</version>
                  <configuration>
                      <propertyFile>target/classes/application.properties</propertyFile>
                  </configuration>
              </plugin>
      
          </plugins>
      
          <filters>
              <filter>src/main/filters/filter.properties</filter>
          </filters>
          <resources>
              <resource>
                  <directory>src/main/resources</directory>
                  <filtering>true</filtering>
              </resource>
          </resources>
      </build>
      

      请参阅我的 github project 以获得完整的工作解决方案。查看您定义了公共属性的filter.properties 文件,然后在application.properties 文件中引用相同的内容。

      注意:由于这是一个 spring 项目,因此不能将 ${propertyName} 用于 maven 过滤器文件作为 spring 的保留属性占位符语法,而是使用 @propertyName@。对于非弹簧项目${propertyName} 将开箱即用。

      【讨论】:

      • 您好!我试过你的建议,我得到:liquibase.exception.DatabaseException:java.lang.RuntimeException:找不到数据库驱动程序:未指定驱动程序类,无法从 url (${spring.datasource.url})
      • 您好,我希望您在文件中定义属性时,中间没有空格。为了便于阅读,这里只显示了它。您的实际文件应如下所示:spring.datasource.url=jdbc:h2:file:./target/test
        # Keys needed for liquibase maven plugin
        url=${spring.datasource.url} 注意:
        用于描述新行,因为它不允许在 SO cmets 中使用
      • 嗨@Amith Kumar,我已经尝试过你的建议,但我得到了同样的错误。我已经用新的配置和错误数据更新了问题。
      • 用示例项目参考和更多细节更新了我的解决方案,这应该适合你。
      • 属性文件需要相同,对于应用程序要么是 liquibase.如果您使用不同的文件将无法正常工作。或者,如果您使用不同的格式,例如应用程序的“.yml”和 liquibase 的“属性”,也将不起作用。
      猜你喜欢
      • 1970-01-01
      • 2017-09-06
      • 2017-05-20
      • 2014-06-20
      • 2015-09-06
      • 1970-01-01
      • 2016-07-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多