335

在针对 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)

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

4

11 回答 11

736

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

然后运行

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

对数据库有帮助。

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

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

于 2013-09-29T18:20:42.503 回答
68

编辑 2020 年 6 月

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

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

原始答案

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

DELETE FROM DATABASECHANGELOGLOCK;

可能会帮助你。

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

于 2015-05-22T09:34:17.527 回答
28

问题在于 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 或删除该表并重新创建。

于 2013-03-22T09:42:24.167 回答
12

没有提到使用哪个环境来执行 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,请编辑更正。

于 2019-04-04T21:39:14.573 回答
3

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

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

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

于 2014-06-19T14:48:51.853 回答
3

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

SQL:

SELECT gid FROM pg_prepared_xacts WHERE database='database_name';

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

ROLLBACK PREPARED 'gid_obtained_from_above_SQL';
于 2016-04-01T01:34:13.300 回答
2

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

DROP TABLE DATABASECHANGELOGLOCK;
于 2020-04-14T17:14:20.683 回答
1

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

UPDATE DATABASECHANGELOGLOCK SET LOCKED=false, LOCKGRANTED=null, LOCKEDBY=null where ID=1;
于 2021-02-11T13:23:36.663 回答
1

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

使用 Gradle 时,这将是:gradlew releaseLocks

于 2021-04-22T08:53:17.237 回答
0

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

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

或者干脆清理桌子

TRUNCATE TABLE INTERFACE_DATABASECHANGELOGLOCK
于 2022-01-27T16:56:28.850 回答
0

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

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

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

于 2022-02-14T00:35:17.717 回答