web-dev-qa-db-fra.com

Verrou Liquibase - des raisons?

Je comprends cela lors de l'exécution de nombreux scripts liquibase sur un serveur Oracle. SomeComputer c'est moi.

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)

Se pourrait-il que le nombre de sessions/transactions simultanées soit atteint? Quelqu'un a des idées?

213
Peter Isberg

Parfois, si l'application de mise à jour est arrêtée brusquement, le verrou reste bloqué.

Puis courir

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

contre la base de données aide.

Ou vous pouvez simplement supprimer la table DATABASECHANGELOGLOCK, elle sera recréée.

474
Adrian Ber

C'est probablement dû à un processus liquibase tué qui n'a pas libéré son verrou sur la table DATABASECHANGELOGLOCK. Ensuite,

DELETE FROM DATABASECHANGELOGLOCK;

pourrait vous aider.

Edit: La réponse de @Adrian Ber fournit une meilleure solution que celle-ci. Ne le faites que si vous rencontrez des problèmes pour résoudre sa solution.

50
e18r

Le problème était l’implémentation erronée de SequenceExists dans Liquibase. Depuis les changesets avec ces déclarations ont pris un temps très long et a été accidentellement interrompu. Ensuite, essayez à nouveau d’exécuter les scripts liquibase et le verrou a été maintenu.

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

Pour contourner ce problème, utilisez SQL pur:

  <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 est stocké dans la table DATABASECHANGELOCK. Pour supprimer le verrou, il suffit de modifier 1 à 0 ou de supprimer cette table et de la recréer.

22
Peter Isberg

Parfois, tronquer ou supprimer la table DATABASECHANGELOGLOCK ne fonctionne pas. J'utilise la base de données PostgreSQL et suis tombé sur ce problème plusieurs fois. Ce que je fais pour résoudre consiste à annuler les instructions préparées qui s'exécutent en arrière-plan pour cette base de données. Essayez de restaurer toutes les instructions préparées et essayez à nouveau les modifications de liquibase.

SQL:

SELECT gid FROM pg_prepared_xacts WHERE database='database_name';

Si l'instruction ci-dessus renvoie un enregistrement, annulez cette instruction préparée avec l'instruction SQL suivante.

ROLLBACK PREPARED 'gid_obtained_from_above_SQL';
3
CodingFreak

Il n'est pas indiqué quel environnement est utilisé pour exécuter Liquibase. Dans le cas de Spring Boot 2, il est possible d’étendre liquibase.lockservice.StandardLockService sans avoir à exécuter d’instructions SQL directes, ce qui est beaucoup plus propre. Par exemple.:

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

Le code impose la libération du verrou. Cela peut être utile dans les configurations de test où l'appel de libération peut ne pas être appelé en cas d'erreur ou lorsque le débogage est abandonné.

La classe doit être placée dans le package liquibase.ext et sera reprise par la configuration automatique de Spring Boot 2.

2
k_o_

J'apprécie que ce ne soit pas le problème du PO, mais je l'ai rencontré récemment pour une autre cause. Pour référence, j'utilisais le plugin Liquibase Maven (liquibase-maven-plugin: 3.1.1) avec SQL Server.

Quoi qu'il en soit, j'avais copié et collé par erreur une instruction "use" SQL Server dans l'un de mes scripts qui permutait les bases de données. Ainsi, liquibase était en cours d'exécution et mettait à jour le DATABASECHANGELOGLOCK. appliquer les modifications. Non seulement je ne pouvais PAS voir mes modifications ou mon audit de liquibase dans la bonne base de données, mais bien entendu, lorsque j’exécutais à nouveau liquibase, il ne pouvait pas obtenir le verrou, car celui-ci avait été relâché dans la "mauvaise" base de données. toujours bloqué dans la base de données "correcte". Je me serais attendu à ce que liquibase vérifie que le verrou était toujours appliqué avant de le relâcher, et c'est peut-être un bogue dans liquibase (je n'ai pas encore vérifié), mais il se peut que ce problème soit résolu dans les versions ultérieures! Cela dit, je suppose que cela pourrait être considéré comme une fonctionnalité!

C'est un peu une erreur d'écolier, je sais, mais je la soulève ici au cas où quelqu'un rencontrerait le même problème!

0
DarthPablo