ChatGPT解决这个技术问题 Extra ChatGPT

Liquibase lock - reasons?

I get this when running a lot of liquibase-scripts against a Oracle-server. SomeComputer is me.

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)

Could it be that the number of simultaneous sessions/transactions are reached? Anyone has any ideas?

Did you kill the JVM while liquibase held the lock? That's the only case where this occurs for me.
There seems to be another PC involved: Konsultpc74. Maybe you ran liquibase from to different PCs at the same time? If not do you have an explanation for the other PC?
I edited the logs and I accidently forgot to change that to SomeComputer
Are you executing the changesets simultaneously? I thought each file and each changeset in it is executed one by one. At least I use it this way. I have one master changeset file which inlcudes all others and everthing is run one by one.

A
Adrian Ber

Sometimes if the update application is abruptly stopped, then the lock remains stuck.

Then running

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

against the database helps.

You may also need to replace LOCKED=0 with LOCKED=FALSE.

Or you can simply drop the DATABASECHANGELOGLOCK table, it will be recreated.


I needed to switch out the 0 for FALSE, but other than that, it worked fine. Thanks
There is a built-in command in Liquibase called releaseLocks that would execute what @Adrian Ber answered but I think it is database agnostic.
I was just getting this error in my development environment. Fixing up the DATABASECHANGELOGLOCK table solved it.
I needed to switch out the FALSE for b'0'
This is the correct solution, don't try emptying the table as that won't help. Either DROP it or UPDATE the LOCKED flag to 'FALSE'
a
aarowman

Edit june 2020

Don't follow this advice. It's caused trouble to many people over the years. It worked for me a long time ago and I posted it in good faith, but it's clearly not the way to do it. The DATABASECHANGELOCK table needs to have stuff in it, so it's a bad idea to just delete everything from it without dropping the table.

Leos Literak, for instance, followed these instructions and the server failed to start.

Original answer

It's possibly due to a killed liquibase process not releasing its lock on the DATABASECHANGELOGLOCK table. Then,

DELETE FROM DATABASECHANGELOGLOCK;

might help you.

Edit: @Adrian Ber's answer provides a better solution than this. Only do this if you have any problems doing his solution.


This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post.
@Rachcha I explained it better. Hope you like it more like this.
Do not follow the advice above. DATABASECHANGELOGLOCK must contain rows without any rows you will get an exception
This does not help, I tried this rather than dropping the table or update locked state to 'false'. It didn't worked.
If you follow this answer there is a good chance future scripts will not run because they expect the lock to exist. If you have done this already you can add an empty lock to fix the issue INSERT INTO yourdb.DATABASECHANGELOGLOCK VALUES (1, 0, null, null);
P
Peter Bratton

The problem was the buggy implementation of SequenceExists in Liquibase. Since the changesets with these statements took a very long time and was accidently aborted. Then the next try executing the liquibase-scripts the lock was held.

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

A work around is using plain SQL to check this instead:

  <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 is stored in the table DATABASECHANGELOCK. To get rid of the lock you just change 1 to 0 or drop that table and recreate.


In liquibase 3.0.2 (the version I am using), do not remove the one line from the lock table, or you will have a different error when running liquibase the next time, because liquibase expects that one row to be there (or the whole table missing). Exactly as Peter said, just wanted to add that info, because in older versions it seems to have worked to also remove the row.
k
k_o_

It is not mentioned which environment is used for executing Liquibase. In case it is Spring Boot 2 it is possible to extend liquibase.lockservice.StandardLockService without the need to run direct SQL statements which is much cleaner. E.g.:

/**
 * 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();
    }
}

The code is enforcing the release of the lock. This can be useful in test setups where the release call might not get called in case of errors or when the debugging is aborted.

The class must be placed in the liquibase.ext package and will be picked up by the Spring Boot 2 auto configuration.

Liquibase 4

Note that the extension loading mechanism has changed in Liquibase 4.

Now a file under META-INF/services with the implemented full interface package name must be created and in this file all extension must be listed.

This could mean that in META-INF/services/liquibase.lockservice.LockService

This line must be added:

com.company.liquibase.impl.ForceReleaseLockService

I have not tried it, still using Liquibase 3, please edit and correct.


Could you please provide a more detailed description of your solution? We use Spring Boot 2 and liquibase and do not want to delete the lock-state in the db each time manually. But I did not understand how do you inject the ForceReleaseLockService to the liquibase. Don`t I have to put a Service/Component annotation over this class, that Spring choose it as a primary bean?
It is mentioned in the last sentence: "The class must be placed in the liquibase.ext package and will be picked up by the Spring Boot 2 auto configuration."
How do you place the class in liquibase.ext, do I need to define that package in my project?
I defined that package in my project, it seems to work but I can't verify it. I defined a @PostConstruct method with a log message but I don't see it printed.
@akuma8: Yes, just create a package in your project with that name. Where did you define the @PostConstruct method? In the ForceReleaseLockService? This is not a Spring service, so this will not get invoked.
M
Mike

You can safely delete the table manually or using query. It will be recreated automatically.

DROP TABLE DATABASECHANGELOGLOCK;

D
DarthPablo

I appreciate this wasn't the OP's issue, but I ran into this issue recently with a different cause. For reference, I was using the Liquibase Maven plugin (liquibase-maven-plugin:3.1.1) with SQL Server.

Anyway, I'd erroneously copied and pasted a SQL Server "use" statement into one of my scripts that switches databases, so liquibase was running and updating the DATABASECHANGELOGLOCK, acquiring the lock in the correct database, but then switching databases to apply the changes. Not only could I NOT see my changes or liquibase audit in the correct database, but of course, when I ran liquibase again, it couldn't acquire the lock, as the lock had been released in the "wrong" database, and so was still locked in the "correct" database. I'd have expected liquibase to check the lock was still applied before releasing it, and maybe that is a bug in liquibase (I haven't checked yet), but it may well be addressed in later versions! That said, I suppose it could be considered a feature!

Quite a bit of a schoolboy error, I know, but I raise it here in case anyone runs into the same problem!


P
Pang

Sometimes truncating or dropping the table DATABASECHANGELOGLOCK doesn't work. I use PostgreSQL database and came across this issue a lot of times. What I do for solving is to rollback the prepared statements running in background for that database. Try to rollback all the prepared statements and try the liquibase changes again.

SQL:

SELECT gid FROM pg_prepared_xacts WHERE database='database_name';

If above statement returns any record, then rollback that prepared statement with following SQL statement.

ROLLBACK PREPARED 'gid_obtained_from_above_SQL';

D
Danny

Please let Liquibase handle its own tables. The correct thing to do, as user1434769 mentions, is to use Liquibase's releaseLocks command.

When using Gradle, this would be: gradlew releaseLocks


g
g.momo

In postgres 12 I needed to use this command:

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

S
Sprooose

I have previously just truncated the DatabaseChangeLogLock table when a lock remained after failure (and this generally still works for me).

However, this project (https://github.com/blagerweij/liquibase-sessionlock) now exists, which uses native database session locks for locking Liquibase when using Oracle, PostgreSQL and MySQL.

The JAR file can be dropped into an existing Liquibase 4.x+ application, and will be automatically detected by Liquibase. This will use session locks for locking.. which are automatically released if the application crashes or is shutdown whilst the lock is held. This will potentially stop the locked state from occuring (if you are using one of the supported databases)


m
malek yahyaoui

If the solution posted by @Adrian didn't work, you may try to do the same in the table INTERFACE_DATABASECHANGELOGLOCK which contains additional informations regarding the lock.

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

or simply clear the table

TRUNCATE TABLE INTERFACE_DATABASECHANGELOGLOCK

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

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now