Serrure Liquibase - raisons?

264

Je l'obtiens lors de l'exécution de nombreux scripts de base de données 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?

Peter Isberg
la source
2
Avez-vous tué la JVM alors que la base de données tenait le verrou? C'est le seul cas où cela se produit pour moi.
Christoph Leiter
Il semble y avoir un autre PC impliqué: Konsultpc74. Peut-être avez-vous exécuté Liquibase depuis différents PC en même temps? Sinon, avez-vous une explication pour l'autre PC?
Jens
J'ai modifié les journaux et j'ai accidentellement oublié de changer cela en SomeComputer
Peter Isberg
Exécutez-vous les ensembles de modifications simultanément? J'ai pensé que chaque fichier et chaque ensemble de modifications qu'il contient sont exécutés un par un. Au moins, je l'utilise de cette façon. J'ai un fichier de modifications principal qui inclut tous les autres et tout est exécuté un par un.
Jens

Réponses:

574

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

Puis en cours d'exécution

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

contre la base de données aide.

Ou vous pouvez simplement laisser tomber la DATABASECHANGELOGLOCKtable, elle sera recréée.

Adrian Ber
la source
24
J'avais besoin de changer le 0for FALSE, mais à part ça, ça fonctionnait bien. Merci
mattalxndr
7
Il existe une commande intégrée dans Liquibase appelée releaseLocks qui exécuterait ce à quoi @Adrian Ber a répondu, mais je pense que c'est indépendant de la base de données.
1
Je venais de recevoir cette erreur dans mon environnement de développement. La correction de la table DATABASECHANGELOGLOCK l'a résolu.
Naymesh Mistry
1
J'avais besoin de changer le FALSEpourb'0'
OrangePot
2
C'est la bonne solution, n'essayez pas de vider la table car cela n'aidera pas. Soit DROP it, soit UPDATE le drapeau VERROUILLÉ sur 'FALSE'
Aditya T
55

Modifier juin 2020

Ne suivez pas ce conseil. Cela a causé des problèmes à de nombreuses personnes au fil des ans. Cela a fonctionné pour moi il y a longtemps et je l'ai affiché de bonne foi, mais ce n'est clairement pas la façon de le faire. La table DATABASECHANGELOCK doit contenir des éléments, c'est donc une mauvaise idée de tout supprimer.

Leos Literak , par exemple, a suivi ces instructions et le serveur n'a pas pu démarrer.

Réponse originale

C'est peut-être dû à un processus de base de données 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 cela. Ne faites cela que si vous rencontrez des problèmes pour trouver sa solution.

e18r
la source
1
Cela ne fournit pas de réponse à la question. Pour critiquer ou demander des éclaircissements à un auteur, laissez un commentaire sous son article.
Rachcha
@Rachcha Je l'ai mieux expliqué. J'espère que vous l'aimez plus comme ça.
e18r
12
Ne suivez pas les conseils ci-dessus. DATABASECHANGELOGLOCK doit contenir des lignes sans aucune ligne, vous obtiendrez une exception
odedsh
Cela n'aide pas, j'ai essayé cela plutôt que de laisser tomber la table ou de mettre à jour l'état verrouillé sur 'false'. Ça n'a pas marché.
Aditya T
Si vous suivez cette réponse, il y a de fortes chances que les futurs scripts ne s'exécutent pas car ils s'attendent à ce que le verrou existe. Si vous l'avez déjà fait, vous pouvez ajouter un verrou vide pour résoudre le problème INSERT INTO yourdb.DATABASECHANGELOGLOCK VALUES (1, 0, null, null);
Rudi Kershaw
24

Le problème était l'implémentation buggy de SequenceExists dans Liquibase. Depuis les changements avec ces déclarations ont pris très longtemps et ont été accidentellement avortés. Ensuite, lors de la prochaine tentative d'exécution des scripts de base de données, 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>

Une solution de contournement utilise du SQL brut pour vérifier cela à la place:

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

Les données de verrouillage sont stockées dans la table DATABASECHANGELOCK. Pour vous débarrasser du verrou, changez simplement 1 en 0 ou déposez ce tableau et recréez.

Peter Isberg
la source
1
Dans liquibase 3.0.2 (la version que j'utilise), ne supprimez pas une ligne de la table de verrouillage, sinon vous aurez une erreur différente lors de l'exécution de liquibase la prochaine fois, car liquibase s'attend à ce qu'une ligne soit là (ou le table entière manquante). Exactement comme l'a dit Peter, je voulais juste ajouter cette information, car dans les anciennes versions, il semble avoir travaillé pour supprimer également la ligne.
Kariem
7

Il n'est pas indiqué quel environnement est utilisé pour exécuter Liquibase. Dans le cas où il s'agit de Spring Boot 2, il est possible d'étendre liquibase.lockservice.StandardLockServicesans avoir besoin d'exécuter des 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 liquibase.extpackage et sera récupérée par la configuration automatique de Spring Boot 2.

k_o_
la source
Pourriez-vous fournir une description plus détaillée de votre solution? Nous utilisons Spring Boot 2 et liquibase et ne voulons pas supprimer manuellement l'état de verrouillage dans la base de données. Mais je n'ai pas compris comment injecter le ForceReleaseLockService à la base de données. Ne dois-je pas mettre une annotation Service / Composant sur cette classe, que Spring la choisisse comme bean primaire?
Andrej Tihonov
1
Il est mentionné dans la dernière phrase: "La classe doit être placée dans le package liquibase.ext et sera récupérée par la configuration automatique de Spring Boot 2."
k_o_
Comment placez-vous la classe liquibase.ext, dois-je définir ce package dans mon projet?
akuma8
J'ai défini ce package dans mon projet, il semble fonctionner mais je ne peux pas le vérifier. J'ai défini une @PostConstructméthode avec un message de journal mais je ne le vois pas imprimé.
akuma8
@ akuma8: Oui, créez simplement un package dans votre projet avec ce nom. Où avez-vous défini la @PostConstructméthode? Dans ForceReleaseLockService? Ce n'est pas un service Spring, donc cela ne sera pas invoqué.
k_o_
3

Parfois, tronquer ou supprimer la table DATABASECHANGELOGLOCK ne fonctionne pas. J'utilise la base de données PostgreSQL et j'ai rencontré ce problème plusieurs fois. Ce que je fais pour résoudre, c'est d'annuler les instructions préparées s'exécutant 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 la base de données.

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';
Koushik Ravulapelli
la source
1

Vous pouvez supprimer le tableau en toute sécurité manuellement ou à l'aide d'une requête. Il sera recréé automatiquement.

DROP TABLE DATABASECHANGELOGLOCK;
Mike
la source
0

J'apprécie que ce n'était pas le problème du PO, mais j'ai rencontré ce problème récemment avec une cause différente. 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" de SQL Server dans l'un de mes scripts qui change de base de données, donc liquibase exécutait et mettait à jour le DATABASECHANGELOGLOCK, obtenant le verrou dans la base de données correcte, puis changeant de base de données pour appliquer les modifications. Non seulement je ne pouvais PAS voir mes modifications ou l'audit de la base de données dans la bonne base de données, mais bien sûr, lorsque je réexécutais la base de données, il ne pouvait pas acquérir le verrou, car le verrou avait été libéré dans la "mauvaise" base de données, et il en était de même pour toujours verrouillé dans la base de données "correcte". Je m'attendais à 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 ne l'ai pas encore vérifié), mais il pourrait bien être corrigé dans les versions ultérieures! Cela dit, je suppose que cela pourrait être considéré comme une fonctionnalité!

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

DarthPablo
la source