Liquibase Lock - Gründe?

261

Ich bekomme das, wenn ich viele Liquibase-Skripte auf einem Oracle-Server ausführe. SomeComputer bin ich.

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)

Könnte es sein, dass die Anzahl der gleichzeitigen Sitzungen / Transaktionen erreicht wird? Hat jemand irgendwelche Ideen?

Peter Isberg
quelle
2
Haben Sie die JVM getötet, während Liquibase das Schloss hielt? Das ist der einzige Fall, in dem dies für mich auftritt.
Christoph Leiter
Es scheint sich um einen anderen PC zu handeln: Konsultpc74. Vielleicht haben Sie gleichzeitig Liquibase auf verschiedene PCs übertragen? Wenn nicht, haben Sie eine Erklärung für den anderen PC?
Jens
Ich habe die Protokolle bearbeitet und versehentlich vergessen, dies in SomeComputer
Peter Isberg am
Führen Sie die Änderungssätze gleichzeitig aus? Ich dachte, jede Datei und jeder Änderungssatz darin wird einzeln ausgeführt. Zumindest benutze ich es so. Ich habe eine Master-Änderungssatzdatei, die alle anderen enthält, und alles wird einzeln ausgeführt.
Jens

Antworten:

571

Manchmal, wenn die Update-Anwendung abrupt gestoppt wird, bleibt die Sperre bestehen.

Dann rennen

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

gegen die Datenbank hilft.

Oder Sie können die DATABASECHANGELOGLOCKTabelle einfach fallen lassen , sie wird neu erstellt.

Adrian Ber
quelle
24
Ich brauchte die zum Schalter heraus 0für FALSE, aber anders als das, es hat gut funktioniert. Danke
mattalxndr
7
In Liquibase gibt es einen integrierten Befehl namens releaseLocks, der die Antwort von @Adrian Ber ausführt, aber ich denke, er ist datenbankunabhängig.
1
Ich habe gerade diesen Fehler in meiner Entwicklungsumgebung erhalten. Das Korrigieren der DATABASECHANGELOGLOCK-Tabelle hat das Problem behoben.
Naymesh Mistry
1
Ich musste den FALSEforb'0'
OrangePot
2
Dies ist die richtige Lösung. Versuchen Sie nicht, die Tabelle zu leeren, da dies nicht hilft. Entweder DROP it oder UPDATE der LOCKED-Flagge auf 'FALSE'
Aditya T
55

Edit Juni 2020

Befolgen Sie diesen Rat nicht. Es hat vielen Menschen im Laufe der Jahre Probleme bereitet. Es hat vor langer Zeit bei mir funktioniert und ich habe es in gutem Glauben veröffentlicht, aber es ist eindeutig nicht der richtige Weg, dies zu tun. Die DATABASECHANGELOCK-Tabelle muss Inhalte enthalten, daher ist es eine schlechte Idee, einfach alles daraus zu löschen.

Leos Literak beispielsweise befolgte diese Anweisungen und der Server konnte nicht gestartet werden.

Ursprüngliche Antwort

Möglicherweise liegt es daran, dass ein abgebrochener Liquibase-Prozess seine Sperre für die DATABASECHANGELOGLOCK-Tabelle nicht aufhebt. Dann,

DELETE FROM DATABASECHANGELOGLOCK;

könnte dir helfen.

Bearbeiten: Die Antwort von @Adrian Ber bietet eine bessere Lösung als diese. Tun Sie dies nur, wenn Sie Probleme bei der Lösung haben.

e18r
quelle
1
Dies gibt keine Antwort auf die Frage. Um einen Autor zu kritisieren oder um Klarstellung zu bitten, hinterlassen Sie einen Kommentar unter seinem Beitrag.
Rachcha
@ Rachcha Ich habe es besser erklärt. Hoffe es gefällt euch eher so.
e18r
12
Befolgen Sie nicht die obigen Hinweise. DATABASECHANGELOGLOCK muss Zeilen ohne Zeilen enthalten. Sie erhalten eine Ausnahme
odedsh
Dies hilft nicht, ich habe dies versucht, anstatt die Tabelle zu löschen oder den gesperrten Status auf "false" zu aktualisieren. Es hat nicht funktioniert.
Aditya T
Wenn Sie dieser Antwort folgen, besteht eine gute Chance, dass zukünftige Skripte nicht ausgeführt werden, da sie erwarten, dass die Sperre vorhanden ist. Wenn Sie dies bereits getan haben, können Sie ein leeres Schloss hinzufügen, um das Problem zu beheben INSERT INTO yourdb.DATABASECHANGELOGLOCK VALUES (1, 0, null, null);
Rudi Kershaw
24

Das Problem war die fehlerhafte Implementierung von SequenceExists in Liquibase. Da die Änderungssätze mit diesen Aussagen sehr lange gedauert haben und versehentlich abgebrochen wurden. Beim nächsten Versuch, die Liquibase-Skripte auszuführen, wurde die Sperre gehalten.

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

Eine Problemumgehung verwendet stattdessen einfaches SQL, um dies zu überprüfen:

  <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>

Sperrdaten werden in der Tabelle DATABASECHANGELOCK gespeichert. Um die Sperre aufzuheben, ändern Sie einfach 1 in 0 oder löschen diese Tabelle und erstellen sie neu.

Peter Isberg
quelle
1
Entfernen Sie in Liquibase 3.0.2 (der von mir verwendeten Version) nicht die eine Zeile aus der Sperrtabelle, da sonst beim nächsten Ausführen von Liquibase ein anderer Fehler auftritt, da Liquibase erwartet, dass eine Zeile vorhanden ist (oder die ganze Tabelle fehlt). Genau wie Peter sagte, wollte ich nur diese Informationen hinzufügen, weil es in älteren Versionen anscheinend funktioniert hat, auch die Zeile zu entfernen.
Kariem
7

Es wird nicht erwähnt, welche Umgebung zum Ausführen von Liquibase verwendet wird. Wenn es sich um Spring Boot 2 handelt, kann es erweitert werden, liquibase.lockservice.StandardLockServiceohne dass direkte SQL-Anweisungen ausgeführt werden müssen, was viel sauberer ist. Z.B:

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

Der Code erzwingt die Freigabe der Sperre. Dies kann bei Test-Setups hilfreich sein, bei denen der Release-Aufruf bei Fehlern möglicherweise nicht aufgerufen wird oder wenn das Debuggen abgebrochen wird.

Die Klasse muss im liquibase.extPaket enthalten sein und wird von der automatischen Konfiguration von Spring Boot 2 übernommen.

k_o_
quelle
Könnten Sie bitte eine detailliertere Beschreibung Ihrer Lösung geben? Wir verwenden Spring Boot 2 und liquibase und möchten den Sperrstatus in der Datenbank nicht jedes Mal manuell löschen. Aber ich habe nicht verstanden, wie Sie den ForceReleaseLockService in die Liquibase injizieren. Muss ich dieser Klasse keine Service / Component-Annotation hinzufügen, damit Spring sie als primäre Bean auswählt?
Andrej Tihonov
1
Im letzten Satz wird erwähnt: "Die Klasse muss im Paket liquibase.ext abgelegt sein und wird von der automatischen Konfiguration von Spring Boot 2 übernommen."
k_o_
Wie platzieren Sie die Klasse liquibase.ext? Muss ich dieses Paket in meinem Projekt definieren?
Akuma8
Ich habe dieses Paket in meinem Projekt definiert, es scheint zu funktionieren, aber ich kann es nicht überprüfen. Ich habe eine @PostConstructMethode mit einer Protokollnachricht definiert, sehe sie jedoch nicht gedruckt.
Akuma8
@ akuma8: Ja, erstellen Sie einfach ein Paket in Ihrem Projekt mit diesem Namen. Wo haben Sie die @PostConstructMethode definiert ? Im ForceReleaseLockService? Dies ist kein Spring-Service, daher wird dieser nicht aufgerufen.
k_o_
3

Manchmal funktioniert das Abschneiden oder Löschen der Tabelle DATABASECHANGELOGLOCK nicht. Ich benutze die PostgreSQL-Datenbank und bin oft auf dieses Problem gestoßen. Zum Lösen rolle ich die vorbereiteten Anweisungen zurück, die im Hintergrund für diese Datenbank ausgeführt werden. Versuchen Sie, alle vorbereiteten Anweisungen zurückzusetzen und die Änderungen an der Liquibase erneut durchzuführen.

SQL:

SELECT gid FROM pg_prepared_xacts WHERE database='database_name';

Wenn die obige Anweisung einen Datensatz zurückgibt, setzen Sie diese vorbereitete Anweisung mit der folgenden SQL-Anweisung zurück.

ROLLBACK PREPARED 'gid_obtained_from_above_SQL';
Koushik Ravulapelli
quelle
1

Sie können die Tabelle sicher manuell oder mithilfe einer Abfrage löschen. Es wird automatisch neu erstellt.

DROP TABLE DATABASECHANGELOGLOCK;
Mike
quelle
0

Ich schätze, dass dies nicht das Problem des OP war, aber ich bin kürzlich auf dieses Problem mit einer anderen Ursache gestoßen. Als Referenz habe ich das Liquibase Maven-Plugin (Liquibase-Maven-Plugin: 3.1.1) mit SQL Server verwendet.

Wie auch immer, ich hatte fälschlicherweise eine SQL Server-Anweisung "use" kopiert und in eines meiner Skripte eingefügt, mit dem Datenbanken gewechselt werden. Daher wurde liquibase ausgeführt und aktualisiert DATABASECHANGELOGLOCK, wobei die Sperre in der richtigen Datenbank erworben und dann die Datenbanken gewechselt wurden , um die Änderungen zu übernehmen. Ich konnte nicht nur meine Änderungen oder das Liquibase-Audit NICHT in der richtigen Datenbank sehen, sondern beim erneuten Ausführen von Liquibase konnte die Sperre natürlich nicht erworben werden, da die Sperre in der "falschen" Datenbank freigegeben wurde und dies auch war immer noch in der "richtigen" Datenbank gesperrt. Ich hätte erwartet, dass Liquibase überprüft, ob das Schloss noch angewendet wurde, bevor es freigegeben wurde, und vielleicht ist das ein Fehler in Liquibase (ich habe es noch nicht überprüft), aber es wird möglicherweise in späteren Versionen behoben! Das heißt, ich nehme an, es könnte als Feature betrachtet werden!

Ich weiß, ein ziemlicher Schuljungenfehler, aber ich spreche ihn hier an, falls jemand auf das gleiche Problem stößt!

DarthPablo
quelle