Liquibase lock - ragioni?


264

Ottengo questo quando eseguo molti script liquibase contro un server Oracle. SomeComputer sono io.

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)

Potrebbe essere raggiunto il numero di sessioni / transazioni simultanee? Qualcuno ha qualche idea?


2
Hai ucciso la JVM mentre la liquibase teneva il lucchetto? Questo è l'unico caso in cui ciò accade per me.
Christoph Leiter,

Sembra che ci sia un altro PC coinvolto: Konsultpc74. Forse hai eseguito liquibase da diversi PC contemporaneamente? In caso contrario, hai una spiegazione per l'altro PC?
Jens,

Ho modificato i registri e per sbaglio ho dimenticato di cambiarlo in SomeComputer
Peter Isberg

Stai eseguendo i changeset contemporaneamente? Ho pensato che ogni file e ogni changeset in esso fosse eseguito uno per uno. Almeno lo uso così. Ho un file principale del changeset che include tutti gli altri e tutto viene eseguito uno per uno.
Jens,

Risposte:


574

A volte se l'applicazione di aggiornamento viene interrotta bruscamente, il blocco rimane bloccato.

Quindi correndo

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

contro il database aiuta.

Oppure puoi semplicemente abbandonare il DATABASECHANGELOGLOCKtavolo, verrà ricreato.


24
Avevo bisogno di cambiare il 0for FALSE, ma a parte questo, ha funzionato bene. Grazie
mattalxndr il

7
C'è un comando integrato in Liquibase chiamato releaseLocks che eseguirà ciò che ha risposto @Adrian Ber ma penso che sia indipendente dal database.

1
Stavo ottenendo questo errore nel mio ambiente di sviluppo. Risolto il problema con la correzione della tabella DATABASECHANGELOGLOCK.
Naymesh Mistry,

1
Avevo bisogno di cambiare FALSEperb'0'
OrangePot il

2
Questa è la soluzione corretta, non provare a svuotare la tabella in quanto non sarà di aiuto. O DROP it o AGGIORNA la bandiera BLOCCATA su 'FALSE'
Aditya T

55

Modifica giugno 2020

Non seguire questo consiglio. Nel corso degli anni ha causato problemi a molte persone. Ha funzionato per me molto tempo fa e l'ho pubblicato in buona fede, ma chiaramente non è il modo di farlo. La tabella DATABASECHANGELOCK deve contenere degli elementi, quindi è una cattiva idea eliminare tutto da esso.

Leos Literak , ad esempio, ha seguito queste istruzioni e il server non è stato avviato.

Risposta originale

Probabilmente è dovuto a un processo di liquibase ucciso che non rilascia il blocco sulla tabella DATABASECHANGELOGLOCK. Poi,

DELETE FROM DATABASECHANGELOGLOCK;

potrebbe aiutarti.

Modifica: la risposta di @Adrian Ber offre una soluzione migliore di questa. Fallo solo in caso di problemi con la sua soluzione.


1
Questo non fornisce una risposta alla domanda. Per criticare o richiedere chiarimenti a un autore, lascia un commento sotto il suo post.
Rachcha,

@Rachcha l'ho spiegato meglio. Spero ti piaccia di più così.
e18r

12
Non seguire i consigli sopra. DATABASECHANGELOGLOCK deve contenere righe senza righe per ottenere un'eccezione
odedsh

Questo non aiuta, l'ho provato piuttosto che far cadere la tabella o aggiornare lo stato bloccato su "false". Non ha funzionato
Aditya T,

Se segui questa risposta, ci sono buone probabilità che gli script futuri non vengano eseguiti perché si aspettano che esista il blocco. Se lo hai già fatto, puoi aggiungere un blocco vuoto per risolvere il problema INSERT INTO yourdb.DATABASECHANGELOGLOCK VALUES (1, 0, null, null);
Rudi Kershaw,

24

Il problema era l'implementazione errata di SequenceExists in Liquibase. Dal momento che i cambiamenti con queste affermazioni impiegarono molto tempo e furono accidentalmente interrotti. Quindi il tentativo successivo di eseguire gli script liquibase il blocco è stato tenuto.

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

Una soluzione è utilizzare SQL semplice per verificare questo invece:

  <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 è memorizzato nella tabella DATABASECHANGELOCK. Per sbarazzarsi del blocco è sufficiente modificare da 1 a 0 o rilasciare quella tabella e ricreare.


1
In liquibase 3.0.2 (la versione che sto usando), non rimuovere una riga dalla tabella di blocco, altrimenti si verificherà un errore diverso quando si esegue liquibase la volta successiva, poiché liquibase prevede che una riga sia presente (o manca l'intero tavolo). Esattamente come disse Peter, volevo solo aggiungere quelle informazioni, perché nelle versioni precedenti sembra aver funzionato anche per rimuovere la riga.
Kariem,

7

Non viene indicato quale ambiente viene utilizzato per eseguire Liquibase. Nel caso in cui sia Spring Boot 2, è possibile estenderlo liquibase.lockservice.StandardLockServicesenza la necessità di eseguire istruzioni SQL dirette che sono molto più pulite. Per esempio:

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

Il codice impone il rilascio del blocco. Ciò può essere utile nelle impostazioni di test in cui la chiamata di rilascio potrebbe non essere chiamata in caso di errori o quando il debug viene interrotto.

La classe deve essere inserita nel liquibase.extpacchetto e verrà prelevata dalla configurazione automatica di Spring Boot 2.


Potresti fornire una descrizione più dettagliata della tua soluzione? Usiamo Spring Boot 2 e liquibase e non vogliamo cancellare manualmente lo stato di blocco nel db. Ma non ho capito come iniettare ForceReleaseLockService nella liquibase. Non devo mettere un'annotazione di servizio / componente su questa classe, che Spring lo ha scelto come bean primario?
Andrej Tihonov,

1
È menzionato nell'ultima frase: "La classe deve essere inserita nel pacchetto liquibase.ext e sarà prelevata dalla configurazione automatica di Spring Boot 2".
k_o_

Come si inserisce la classe liquibase.ext , devo definire quel pacchetto nel mio progetto?
Akuma8,

Ho definito quel pacchetto nel mio progetto, sembra funzionare ma non riesco a verificarlo. Ho definito a@PostConstruct metodo con un messaggio di registro ma non lo vedo stampato.
Akuma8

@ Akuma8: Sì, crea un pacchetto nel tuo progetto con quel nome. Dove hai definito il @PostConstructmetodo? Nel ForceReleaseLockService? Questo non è un servizio Spring, quindi non verrà invocato.
k_o_

3

A volte troncare o far cadere la tabella DATABASECHANGELOGLOCK non funziona. Uso il database PostgreSQL e ho riscontrato questo problema molte volte. Quello che faccio per risolvere è il rollback delle istruzioni preparate in esecuzione in background per quel database. Prova a ripristinare tutte le istruzioni preparate e riprova a modificare le modifiche alla liquibase.

SQL:

SELECT gid FROM pg_prepared_xacts WHERE database='database_name';

Se l'istruzione precedente restituisce qualsiasi record, ripristina l'istruzione preparata con la seguente istruzione SQL.

ROLLBACK PREPARED 'gid_obtained_from_above_SQL';

1

È possibile eliminare in modo sicuro la tabella manualmente o utilizzando la query. Sarà ricreato automaticamente.

DROP TABLE DATABASECHANGELOGLOCK;

0

Apprezzo che questo non sia stato il problema del PO, ma di recente ho riscontrato questo problema per una causa diversa. Per riferimento, stavo usando il plugin Liquibase Maven (liquibase-maven-plugin: 3.1.1) con SQL Server.

Ad ogni modo, avevo erroneamente copiato e incollato un'istruzione "use" di SQL Server in uno dei miei script che cambia database, quindi liquibase era in esecuzione e aggiornava il DATABASECHANGELOGLOCK , acquisendo il blocco nel database corretto, ma poi cambiando database per applicare le modifiche. Non solo non ho potuto vedere le mie modifiche o il controllo della liquibase nel database corretto, ma ovviamente, quando ho eseguito nuovamente liquibase, non è stato possibile acquisire il blocco, poiché il blocco era stato rilasciato nel database "sbagliato", e così è stato ancora bloccato nel database "corretto". Mi sarei aspettato che liquibase verificasse che il lucchetto fosse ancora applicato prima di rilasciarlo, e forse questo è un bug in liquibase (non ho ancora controllato), ma potrebbe essere risolto nelle versioni successive! Detto questo, suppongo che potrebbe essere considerato una caratteristica!

Un po 'di errore da scolaretto, lo so, ma lo sollevo qui nel caso qualcuno incontri lo stesso problema!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.