ChatGPT解决这个技术问题 Extra ChatGPT

Liquibase 锁 - 原因?

在针对 Oracle 服务器运行大量 liquibase 脚本时,我得到了这个。 SomeComputer 是我。

Waiting for changelog lock....
Waiting for changelog lock....
Waiting for changelog lock....
Waiting for changelog lock....
Waiting for changelog lock....
Waiting for changelog lock....
Waiting for changelog lock....
Liquibase Update Failed: Could not acquire change log lock.  Currently locked by SomeComputer (192.168.15.X) since 2013-03-20 13:39
SEVERE 2013-03-20 16:59:liquibase: Could not acquire change log lock.  Currently locked by SomeComputer (192.168.15.X) since 2013-03-20 13:39
liquibase.exception.LockException: Could not acquire change log lock.  Currently locked by SomeComputer (192.168.15.X) since 2013-03-20 13:39
        at liquibase.lockservice.LockService.waitForLock(LockService.java:81)
        at liquibase.Liquibase.tag(Liquibase.java:507)
        at liquibase.integration.commandline.Main.doMigration(Main.java:643)
        at liquibase.integration.commandline.Main.main(Main.java:116)

是否达到了同时会话/交易的数量?有人有什么想法吗?

当 liquibase 持有锁时,你是否杀死了 JVM?这是我发生这种情况的唯一情况。
似乎涉及另一台 PC:Konsultpc74。也许您同时将 liquibase 从不同的 PC 运行?如果没有,您对另一台 PC 有解释吗?
我编辑了日志,但我不小心忘记将其更改为 SomeComputer
您是否同时执行变更集?我认为每个文件和其中的每个变更集都是一个一个执行的。至少我是这样用的。我有一个主变更集文件,其中包含所有其他文件,并且一切都被一一运行。

A
Adrian Ber

有时,如果更新应用程序突然停止,则锁仍然卡住。

然后运行

UPDATE DATABASECHANGELOGLOCK SET LOCKED=0, LOCKGRANTED=null, LOCKEDBY=null where ID=1;

对数据库有帮助。

您可能还需要将 LOCKED=0 替换为 LOCKED=FALSE

或者您可以简单地删除 DATABASECHANGELOGLOCK 表,它将被重新创建。


我需要将 0 换成 FALSE,但除此之外,它运行良好。谢谢
Liquibase 中有一个名为 releaseLocks 的内置命令,可以执行@Adrian Ber 回答的内容,但我认为它与数据库无关。
我刚刚在我的开发环境中遇到了这个错误。修复 DATABASECHANGELOGLOCK 表解决了它。
我需要将 FALSE 换成 b'0'
这是正确的解决方案,不要尝试清空表格,因为这无济于事。删除它或将 LOCKED 标志更新为 'FALSE'
a
aarowman

编辑 2020 年 6 月

不要听从这个建议。多年来,它给许多人带来了麻烦。很久以前它对我有用,我真诚地发布了它,但显然不是这样做的方法。 DATABASECHANGELOCK 表中需要有东西,所以不删除表就删除它的所有内容是个坏主意。

例如,Leos Literak 遵循了这些说明,但服务器无法启动。

原始答案

这可能是由于已终止的 liquibase 进程未释放其对 DATABASECHANGELOGLOCK 表的锁定。然后,

DELETE FROM DATABASECHANGELOGLOCK;

可能会帮助你。

编辑:@Adrian Ber 的回答提供了比这更好的解决方案。仅当您在解决他的解决方案时遇到任何问题时才这样做。


这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方留下评论。
@Rachcha 我解释得更好。希望你更喜欢这样。
不要听从上面的建议。 DATABASECHANGELOGLOCK 必须包含没有任何行的行,否则会出现异常
这没有帮助,我尝试了这个,而不是删除表或将锁定状态更新为“假”。它没有用。
如果您遵循这个答案,那么未来的脚本很有可能不会运行,因为它们希望锁存在。如果您已经这样做了,您可以添加一个空锁来解决问题INSERT INTO yourdb.DATABASECHANGELOGLOCK VALUES (1, 0, null, null);
P
Peter Bratton

问题在于 Liquibase 中 SequenceExists 的错误实现。由于这些语句的变更集花费了很长时间并且被意外中止。然后下一次尝试执行持有锁的 liquibase-scripts。

  <changeSet author="user" id="123">
    <preConditions onFail="CONTINUE">
      <not><sequenceExists sequenceName="SEQUENCE_NAME_SEQ" /></not>
    </preConditions>
    <createSequence sequenceName="SEQUENCE_NAME_SEQ"/>
  </changeSet>

一种解决方法是使用纯 SQL 来检查:

  <changeSet author="user" id="123">
    <preConditions onFail="CONTINUE">
            <sqlCheck expectedResult="0">
              select count(*) from user_sequences where sequence_name = 'SEQUENCE_NAME_SEQ';
            </sqlCheck>
    </preConditions>
    <createSequence sequenceName="SEQUENCE_NAME_SEQ"/>
  </changeSet>

Lockdata 存储在表 DATABASECHANGELOCK 中。要摆脱锁定,您只需将 1 更改为 0 或删除该表并重新创建。


在 liquibase 3.0.2(我正在使用的版本)中,不要从锁表中删除这一行,否则下次运行 liquibase 时会出现不同的错误,因为 liquibase 期望有一行(或整张桌子不见了)。正如彼得所说,只是想添加该信息,因为在旧版本中,它似乎也可以删除该行。
k
k_o_

没有提到使用哪个环境来执行 Liquibase。如果是 Spring Boot 2,可以扩展 liquibase.lockservice.StandardLockService 而无需运行更简洁的直接 SQL 语句。例如:

/**
 * This class is enforcing to release the lock from the database.
 *
 */
 public class ForceReleaseLockService extends StandardLockService {

    @Override
    public int getPriority() {
        return super.getPriority()+1;
    }

    @Override
    public void waitForLock() throws LockException {
        try {
            super.forceReleaseLock();
        } catch (DatabaseException e) {
            throw new LockException("Could not enforce getting the lock.", e);
        }
        super.waitForLock();
    }
}

该代码正在强制释放锁。这在测试设置中很有用,因为在出现错误或调试中止时可能不会调用发布调用。

该类必须放在 liquibase.ext 包中,并将由 Spring Boot 2 自动配置获取。

Liquibase 4

请注意,扩展加载机制已在 Liquibase 4 中更改。

现在必须在 META-INF/services 下创建一个具有已实现的完整接口包名称的文件,并且必须在此文件中列出所有扩展名。

这可能意味着在 META-INF/services/liquibase.lockservice.LockService

必须添加此行:

com.company.liquibase.impl.ForceReleaseLockService

没试过,还在用Liquibase 3,请编辑更正。


您能否提供更详细的解决方案描述?我们使用 Spring Boot 2 和 liquibase,不想每次手动删除数据库中的锁定状态。但我不明白你如何将 ForceReleaseLockService 注入到 liquibase。我不必在这个类上放置一个服务/组件注释,Spring 选择它作为主 bean 吗?
在最后一句中提到:“该类必须放在 liquibase.ext 包中,并且会被 Spring Boot 2 自动配置拾取。”
您如何将类放在 liquibase.ext 中,我需要在我的项目中定义该包吗?
我在我的项目中定义了那个包,它似乎可以工作,但我无法验证它。我定义了一个带有日志消息的 @PostConstruct 方法,但我没有看到它被打印出来。
@akuma8:是的,只需在您的项目中使用该名称创建一个包。您在哪里定义了 @PostConstruct 方法?在 ForceReleaseLockService 中?这不是 Spring 服务,因此不会被调用。
M
Mike

您可以手动或使用查询安全地删除表。它将自动重新创建。

DROP TABLE DATABASECHANGELOGLOCK;

D
DarthPablo

我很欣赏这不是 OP 的问题,但我最近遇到了这个问题,原因不同。作为参考,我在 SQL Server 中使用了 Liquibase Maven 插件 (liquibase-maven-plugin:3.1.1)。

无论如何,我错误地将 SQL Server“使用”语句复制并粘贴到我的一个切换数据库的脚本中,因此 liquibase 正在运行并更新 DATABASECHANGELOGLOCK,获取正确数据库中的锁,然后切换数据库以应用变化。我不仅在正确的数据库中看不到我的更改或 liquibase 审计,而且当然,当我再次运行 liquibase 时,它无法获取锁,因为锁已在“错误”数据库中释放,所以是仍然锁定在“正确”的数据库中。我本来希望 liquibase 在释放它之前检查锁是否仍然被应用,也许这是 liquibase 中的一个错误(我还没有检查过),但它很可能在以后的版本中得到解决!也就是说,我想它可以被认为是一个功能!

相当多的小学生错误,我知道,但我在这里提出,以防有人遇到同样的问题!


P
Pang

有时截断或删除表 DATABASECHANGELOGLOCK 不起作用。我使用 PostgreSQL 数据库并多次遇到这个问题。我要解决的是回滚在后台为该数据库运行的准备好的语句。尝试回滚所有准备好的语句并再次尝试 liquibase 更改。

SQL:

SELECT gid FROM pg_prepared_xacts WHERE database='database_name';

如果上述语句返回任何记录,则使用以下 SQL 语句回滚该准备好的语句。

ROLLBACK PREPARED 'gid_obtained_from_above_SQL';

D
Danny

请让 Liquibase 处理自己的表格。正如 user1434769 所提到的,正确的做法是使用 Liquibase 的 releaseLocks 命令。

使用 Gradle 时,这将是:gradlew releaseLocks


g
g.momo

在 postgres 12 中,我需要使用以下命令:

UPDATE DATABASECHANGELOGLOCK SET LOCKED=false, LOCKGRANTED=null, LOCKEDBY=null where ID=1;

S
Sprooose

我之前刚刚截断了 DatabaseChangeLogLock 表,当锁在失败后仍然存在时(这通常对我仍然有效)。

但是,这个项目 (https://github.com/blagerweij/liquibase-sessionlock) 现在存在,它在使用 Oracle、PostgreSQL 和 MySQL 时使用本机数据库会话锁来锁定 Liquibase。

JAR 文件可以拖放到现有的 Liquibase 4.x+ 应用程序中,并由 Liquibase 自动检测。这将使用会话锁进行锁定。如果应用程序崩溃或在持有锁时关闭,会话锁会自动释放。这可能会阻止锁定状态的发生(如果您使用的是受支持的数据库之一)


m
malek yahyaoui

如果@Adrian 发布的解决方案不起作用,您可以尝试在包含有关锁的其他信息的表 INTERFACE_DATABASECHANGELOGLOCK 中执行相同操作。

UPDATE INTERFACE_DATABASECHANGELOGLOCK SET LOCKED=0, LOCKGRANTED=null, LOCKEDBY=null where ID=1;

或者干脆清理桌子

TRUNCATE TABLE INTERFACE_DATABASECHANGELOGLOCK

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅