如何正确使用 liquibase `searchPath` 选项来指示各自的资源文件夹?

Mor*_*aki 7 bash liquibase

我试图调用如下update命令:liquibase

liquibase update --changelog-file=./persistence/src/main/resources/changelog/db.changelog-dev.xml \
                 --url="jdbc:postgresql://localhost:5432/sigma"
Run Code Online (Sandbox Code Playgroud)

这导致:

[...]
Starting Liquibase at 23:44:47 (version 4.17.2 #5255 built at 2022-11-01 18:07+0000)
Liquibase Version: 4.17.2
Liquibase Community 4.17.2 by Liquibase

Unexpected error running Liquibase: The file classpath:/changelog/db.changelog-master.xml was not found in the configured search path:
    - /Users/ikaerom/Dev/sigma-backend
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/liquibase-core.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/lib
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/jaybird.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/ojdbc8.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/snakeyaml.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/snowflake-jdbc.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/picocli.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/jaxb-runtime.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/jaxb-api.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/jaxb-core.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/hsqldb.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/connector-api.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/mssql-jdbc.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/h2.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/mariadb-java-client.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/liquibase-commercial.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/commons-lang3.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/postgresql.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/sqlite-jdbc.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/opencsv.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/commons-text.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/commons-collections4.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/jcc.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib
More locations can be added with the 'searchPath' parameter.
Run Code Online (Sandbox Code Playgroud)

本质上是db.changelog-dev.xmlinclude db.changelog-master.xml,然后它还引用了一些 SQL 脚本。这两个 XML 文件位于同一个资源文件夹中$PROJECT_ROOT/persistence/src/main/resources/changelog。更改日志 XML 中引用的导入/包含的 SQL 文件全部位于资源文件夹的子文件夹中。

任何指定此逃避searchPath甚至参数(如文档--search-path中所示)的方法似乎都会失败:

[...]
Starting Liquibase at 23:44:47 (version 4.17.2 #5255 built at 2022-11-01 18:07+0000)
Liquibase Version: 4.17.2
Liquibase Community 4.17.2 by Liquibase

Unexpected error running Liquibase: The file classpath:/changelog/db.changelog-master.xml was not found in the configured search path:
    - /Users/ikaerom/Dev/sigma-backend
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/liquibase-core.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/lib
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/jaybird.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/ojdbc8.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/snakeyaml.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/snowflake-jdbc.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/picocli.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/jaxb-runtime.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/jaxb-api.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/jaxb-core.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/hsqldb.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/connector-api.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/mssql-jdbc.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/h2.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/mariadb-java-client.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/liquibase-commercial.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/commons-lang3.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/postgresql.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/sqlite-jdbc.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/opencsv.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/commons-text.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/commons-collections4.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib/jcc.jar
    - /opt/homebrew/Cellar/liquibase/4.17.2/libexec/internal/lib
More locations can be added with the 'searchPath' parameter.
Run Code Online (Sandbox Code Playgroud)

那么让我们尝试其他指定的语法:

$> liquibase update --searchPath="./persistence/src/main/resources/" --changelog-file=./persistence/src/main/resources/changelog/db.changelog-dev.xml --url="jdbc:postgresql://localhost:5432/sigma"
Unexpected argument(s): --searchPath=./persistence/src/main/resources/
Run Code Online (Sandbox Code Playgroud)

如果我尝试使用LIQUIBASE_SEARCH_PATH=,我最终会得到这样的结果:

[...]
Liquibase Version: 4.17.2
Liquibase Community 4.17.2 by Liquibase

Liquibase Community detected and ignored the following environment variables:
- LIQUIBASE_SEARCH_PATH
To configure Liquibase with environment variables requires a Liquibase Pro or Liquibase Labs license. Get a free trial at https://liquibase.com/trial. Options include the liquibase.licenseKey in the defaults file, adding a flag in the CLI, and more. Learn more at https://docs.liquibase.com.
[...]
Run Code Online (Sandbox Code Playgroud)

我真的不想只是为了让这个功能发挥作用而购买专业版;)。

我的问题是:如何指定liquibase在 bash shell 中获取它的搜索路径?

我发现很难相信这行不通,因为有liquibase如此详尽的文档记录,并且如果您不正确使用它,它总是试图为您提供正确的提示和指示。我错过了什么?

更新:我怀疑调用顺序很重要。因此,该update命令应该位于列表的最后。然而,到目前为止还没有运气:

$> liquibase update --search-path="./persistence/src/main/resources/" --changelog-file=./persistence/src/main/resources/changelog/db.changelog-dev.xml --url="jdbc:postgresql://localhost:5432/sigma"
Unexpected argument(s): --search-path=./persistence/src/main/resources/
Run Code Online (Sandbox Code Playgroud)

Mor*_*aki 9

在深入研究liquibase源代码后,我自己找到了解决方案。

在我的代码中db.changelog-dev.xm,我有一行内容db.changelog-master.xml如下。classpath:/必须删除它:

-    <include file="classpath:/changelog/db.changelog-master.xml"/>
+    <include file="changelog/db.changelog-master.xml"/>
Run Code Online (Sandbox Code Playgroud)

然后,这个调用终于起作用了(注意参数设置searchPath的调整和相对指定changelog):

-    <include file="classpath:/changelog/db.changelog-master.xml"/>
+    <include file="changelog/db.changelog-master.xml"/>
Run Code Online (Sandbox Code Playgroud)

--hub-mode=off将阻止liquibase询问您是否要连接到 liquibase 集线器。剩下的就是糖衣了。

唯一存在的问题是,当liquibase从 shell CLI 调用时,最终拥有变更日志/锁定表的用户是调用该liquibase命令的用户:

    liquibase \
          --hub-mode=off \
          --headless=true \
          --url="jdbc:postgresql://localhost:5432/sigma" \
          --searchPath="./persistence/src/main/resources" \
          --changelog-file=changelog/db.changelog-dev.xml \
          update 2>&1 | grep -Ev -- "^##"
Run Code Online (Sandbox Code Playgroud)

但是,当liquibase通过调用 Spring boot 应用程序进行更新时,表所有者用户就是应用程序上下文正在设置的用户(在我的例子中为 sigma):

ikaerom@/tmp:sigma> \dt databasechangeloglock
+--------+-----------------------+-------+---------+
| Schema | Name                  | Type  | Owner   |
|--------+-----------------------+-------+---------|
| public | databasechangeloglock | table | ikaerom |
+--------+-----------------------+-------+---------+
SELECT 1
Time: 0.011s
ikaerom@/tmp:sigma> \dt databasechangeloglock
+--------+-----------------------+-------+---------+
| Schema | Name                  | Type  | Owner   |
|--------+-----------------------+-------+---------|
| public | databasechangeloglock | table | ikaerom |
+--------+-----------------------+-------+---------+
SELECT 1
Time: 0.010s
Run Code Online (Sandbox Code Playgroud)

liquibase如果您先运行更新,则会发生冲突:

Caused by: liquibase.exception.DatabaseException: ERROR: relation "databasechangeloglock" already exists [Failed SQL: (0) CREATE TABLE public.databasechangeloglock (ID INTEGER NOT NULL, LOCKED BOOLEAN NOT NULL, LOCKGRANTED TIMESTAMP WITHOUT TIME ZONE, LOCKEDBY VARCHAR(255), CONSTRAINT databasechangeloglock_pkey PRIMARY KEY (ID))]
    at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:397)
    at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:83)
    at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:151)
    at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:135)
    at liquibase.lockservice.StandardLockService.init(StandardLockService.java:115)
    at liquibase.lockservice.StandardLockService.acquireLock(StandardLockService.java:286)
    ... 94 common frames omitted
Caused by: org.postgresql.util.PSQLException: ERROR: relation "databasechangeloglock" already exists
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2675)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2365)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:355)
    at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:490)
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:408)
    at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:329)
    at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:315)
    at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:291)
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:286)
    at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94)
    at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java)
    at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:393)
Run Code Online (Sandbox Code Playgroud)

这同样可以通过对西格玛进行适当的授予或将所有者重新分配给合法用户来解决。或者简单地将该--username属性添加到 Spring Boot 应用程序上下文或数据库用户所有者的名称中:

ikaerom@/tmp:sigma> \dt databasechangeloglock
+--------+-----------------------+-------+-------+
| Schema | Name                  | Type  | Owner |
|--------+-----------------------+-------+-------|
| public | databasechangeloglock | table | sigma |
+--------+-----------------------+-------+-------+
SELECT 1
Time: 0.010s
ikaerom@/tmp:sigma> \dt databasechangelog
+--------+-------------------+-------+-------+
| Schema | Name              | Type  | Owner |
|--------+-------------------+-------+-------|
| public | databasechangelog | table | sigma |
+--------+-------------------+-------+-------+
SELECT 1
Time: 0.009s
Run Code Online (Sandbox Code Playgroud)