Замок Liquibase - причини?


262

Я отримую це під час запуску безлічі скриптів likibase на сервері Oracle. Якийськомп'ютер - це я.

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)

Чи може бути досягнута кількість одночасних сеансів / транзакцій? У когось є якісь ідеї?


2
Ви вбивали JVM, поки ліквід тримав замок? Це єдиний випадок, коли це трапляється для мене.
Крістоф Лейтер

Здається, що задіяний інший ПК: Konsultpc74. Можливо, ви одночасно переходили на інший комп'ютер? Якщо у вас немає пояснення для іншого ПК?
Єнс

Я редагував журнали, і випадково забув змінити це на SomeComputer
Пітер Ісберг

Ви виконуєте набори змін одночасно? Я подумав, що кожен файл і кожен набір змін у ньому виконуються по черзі. Принаймні я цим користуюсь. У мене є один головний файл змін, який включає в себе всі інші, і все працює за одним.
Єнс

Відповіді:


572

Іноді, якщо програма оновлення різко зупинена, блокування залишається застряглим.

Потім біг

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

проти бази даних допомагає.

Або ви можете просто скинути DATABASECHANGELOGLOCKстіл, він буде відтворений.


24
Мені потрібно було вимкнути 0для FALSE, але крім цього, він працював чудово. Спасибі
mattalxndr

7
У Liquibase є вбудована команда під назвою releaseLocks, яка б виконала те, на що відповів @Adrian Ber, але я думаю, що це агностик бази даних.

1
Я тільки отримував цю помилку в моєму середовищі розробки. Виправлення таблиці DATABASECHANGELOGLOCK вирішило це.
Наймеш Містерій

1
Мені потрібно було вимкнути FALSEдляb'0'
OrangePot

2
Це правильне рішення, не намагайтеся спорожнити таблицю, оскільки це не допоможе. Або опустіть його, або ОНОВЛЕННЯ ЗАМЕЧАНОГО прапора на "FALSE"
Aditya T

55

Редагувати червень 2020 року

Не дотримуйтесь цієї поради. Багато років це спричиняло проблеми багатьом людям. Це працювало для мене дуже давно, і я розмістив це сумлінно, але це очевидно не так. Таблиця DATABASECHANGELOCK повинна містити в ній речі, тому погано ідея просто видалити з неї все.

Наприклад, Леос Літерак дотримувався цих інструкцій, і сервер не запустився.

Оригінальна відповідь

Можливо, це пов’язано з тим, що вбитий процес ліквідного вивільнення не відпускає його замок у таблиці DATABASECHANGELOGLOCK. Тоді,

DELETE FROM DATABASECHANGELOGLOCK;

може допомогти вам.

Редагувати: Відповідь Адріана Бер пропонує краще рішення, ніж це. Робіть це лише в тому випадку, якщо у вас виникли проблеми з його вирішенням.


1
Це не дає відповіді на запитання. Щоб критикувати або вимагати роз'яснення у автора, залиште коментар під їх дописом.
Рачча

@Rachcha Я пояснив це краще. Сподіваюсь, вам це більше сподобається.
e18r

12
Не дотримуйтесь наведених вище порад. DATABASECHANGELOGLOCK повинен містити рядки без рядків, ви отримаєте виняток
odedsh

Це не допомагає, я спробував це, замість того, щоб скидати таблицю або оновити заблокований стан на "false". Це не спрацювало.
Aditya T

Якщо ви дотримуєтесь цієї відповіді, є велика ймовірність, що майбутні сценарії не запустяться, оскільки вони очікують, що блокування існуватиме. Якщо ви вже зробили це, ви можете додати порожній замок, щоб вирішити проблему INSERT INTO yourdb.DATABASECHANGELOGLOCK VALUES (1, 0, null, null);
Руді Кершо

24

Проблемою була помилкова реалізація SequenceExists в Liquibase. Оскільки набори змін з цими заявами зайняли дуже багато часу і були випадково перервані. Тоді наступна спроба виконання скриптів liquidibase блокування було проведено.

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

Для роботи це використовується звичайний SQL:

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

Локальні дані зберігаються в таблиці DATABASECHANGELOCK. Щоб позбутися від блокування, просто змініть 1 на 0 або відкиньте цю таблицю і відтворіть її.


1
У liquidibase 3.0.2 (версії, яку я використовую) не видаляйте один рядок із таблиці блокування, інакше ви матимете іншу помилку під час наступного запуску liquidibase, оскільки очікує, що один рядок буде там (або цілий стіл відсутній). Точно так, як Петро сказав, просто хотів додати цю інформацію, оскільки в старих версіях, здається, він працював і над тим, щоб видалити рядок.
Карієм

7

Не зазначається, яке середовище використовується для виконання Liquibase. У випадку, якщо це Spring Boot 2, можна розширити liquibase.lockservice.StandardLockServiceбез необхідності запускати прямі оператори SQL, що набагато чистіше. Наприклад:

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

Код примушує звільнити замок. Це може бути корисно в тестових налаштуваннях, де виклик випуску може не викликатись у випадку помилок або коли налагодження перервано.

Клас повинен бути поміщений в liquibase.extпакет і буде підбиратися автоматичною конфігурацією Spring Boot 2.


Чи можете ви надати більш детальний опис свого рішення? Ми використовуємо Spring Boot 2 та liquidibase і не хочемо кожного разу видаляти стан блокування у db вручну. Але я не зрозумів, як ти вводиш ForceReleaseLockService в ліквідну базу. Не потрібно мені класти анотацію Service / Component над цим класом, щоб весна обрала його як основний боб?
Андрій

1
Він згадується в останньому реченні: "Клас повинен бути поміщений у пакунок liquidibase.ext і буде підхоплений автоматичною конфігурацією Spring Boot 2."
k_o_

Як ви розміщуєте клас liquibase.ext, чи потрібно мені визначати цей пакет у своєму проекті?
akuma8

Я визначив цей пакет у своєму проекті, він, здається, працює, але не можу його перевірити. Я визначив @PostConstructметод із повідомленням журналу, але не бачу його надрукованим.
akuma8

@ akuma8: Так, просто створіть пакет у своєму проекті з таким ім'ям. Де ви визначили @PostConstructметод? У ForceReleaseLockService? Це не весняний сервіс, тому на це не буде звертатися.
k_o_

3

Іноді обрізання або випадання таблиці DATABASECHANGELOGLOCK не працює. Я використовую базу даних PostgreSQL і стикався з цим питанням багато разів. Що я роблю для вирішення - це відкат підготовлених операторів, які працюють у фоновому режимі для цієї бази даних. Спробуйте відкатати всі підготовлені заяви і спробуйте змінити ліквідну базу знову.

SQL:

SELECT gid FROM pg_prepared_xacts WHERE database='database_name';

Якщо вище оператор повертає будь-який запис, тоді відкат цього підготовленого оператора з наступним оператором SQL.

ROLLBACK PREPARED 'gid_obtained_from_above_SQL';

1

Ви можете безпечно видалити таблицю вручну або за допомогою запиту. Він буде відтворений автоматично.

DROP TABLE DATABASECHANGELOGLOCK;

0

Я вдячний, що це не було питанням ОП, але я нещодавно зіткнувся з цим питанням з іншою причиною. Для довідки я використовував плагін Liquibase Maven (liquidibase-maven-plugin: 3.1.1) з сервером SQL.

У будь-якому разі я помилково скопіював і вставив оператор "use" SQL Server в один із моїх сценаріїв, який перемикає бази даних, тому ліквід працює і оновлюється DATABASECHANGELOGLOCK, придбавши замок у правильній базі даних, але потім перемикаючи бази даних, щоб застосувати зміни. Я не тільки не міг бачити мої зміни або аудит ліквідних баз у правильній базі даних, але, звичайно, коли я знову запустив liquidibase, він не міг придбати блокування, оскільки блокування було випущено в "неправильній" базі даних, і так було як і раніше заблокований у "правильній" базі даних. Я б очікував, що програма likibase перевірить, чи застосовано замок, перш ніж випустити його, і, можливо, це помилка в liquidibase (я ще не перевіряв), але це може бути вирішено в пізніших версіях! Це сказав, я думаю, це можна вважати особливістю!

Дуже трохи помилки школяра, я знаю, але я піднімаю це тут, якщо хтось зіткнеться з тією ж проблемою!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.