ล็อค Liquibase - เหตุผล?


262

ฉันได้สิ่งนี้เมื่อใช้สคริปต์ liquibase จำนวนมากกับเซิร์ฟเวอร์ 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 ในขณะที่ liquibase ถือกุญแจอยู่หรือไม่? นั่นเป็นกรณีเดียวที่เกิดขึ้นกับฉัน
Christoph Leiter

ดูเหมือนว่าจะมีพีซีอีกเครื่องที่เกี่ยวข้อง: Konsultpc74 บางทีคุณอาจใช้ของเหลวจากคอมพิวเตอร์เครื่องอื่นไปพร้อม ๆ กัน? ถ้าไม่มีคำอธิบายสำหรับพีซีเครื่องอื่น?
Jens

ฉันแก้ไขบันทึกและฉันลืมเปลี่ยนไปเป็น SomeComputer โดยบังเอิญ
Peter Isberg

คุณกำลังดำเนินการเซ็ตการแก้ไขพร้อมกันหรือไม่? ฉันคิดว่าแต่ละไฟล์และแต่ละเซ็ตการแก้ไขในนั้นเรียกใช้งานทีละไฟล์ อย่างน้อยฉันก็ใช้วิธีนี้ ฉันมีไฟล์เซ็ตการแก้ไขหลักหนึ่งไฟล์ซึ่งรวมถึงไฟล์อื่นทั้งหมดและทุกสิ่งจะถูกเรียกใช้ทีละไฟล์
Jens

คำตอบ:


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 แก้ไขได้
Naymesh Mistry

1
ฉันต้องการเปลี่ยนFALSEสำหรับb'0'
OrangePot

2
นี่เป็นวิธีแก้ไขที่ถูกต้องอย่าพยายามล้างตารางเนื่องจากจะไม่ช่วย DROP มันหรืออัพเดทธงที่ถูกล็อคเป็น 'FALSE'
Aditya T

55

แก้ไขมิถุนายน 2020

อย่าทำตามคำแนะนำนี้ มันทำให้เกิดปัญหากับคนหลายคนในช่วงหลายปีที่ผ่านมา มันใช้งานได้นานแล้วและฉันโพสต์ไว้โดยสุจริต แต่ก็ไม่ใช่วิธีการที่ชัดเจน ตาราง DATABASECHANGELOCK ต้องมีเนื้อหาอยู่ในนั้นดังนั้นจึงเป็นความคิดที่ดีที่จะลบทุกอย่างออกจากมัน

ตัวอย่างเช่นLeos Literakทำตามคำแนะนำเหล่านี้และเซิร์ฟเวอร์ไม่สามารถเริ่มต้นได้

คำตอบเดิม

อาจเป็นเพราะกระบวนการ liquibase ที่ฆ่าแล้วไม่ปล่อยการล็อกบนตาราง DATABASECHANGELOGLOCK จากนั้น

DELETE FROM DATABASECHANGELOGLOCK;

อาจช่วยคุณ

แก้ไข:คำตอบของ @Adrian Ber ให้วิธีแก้ปัญหาที่ดีกว่านี้ ทำเช่นนี้ต่อเมื่อคุณมีปัญหาในการแก้ปัญหาของเขา


1
สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถาม หากต้องการวิจารณ์หรือขอคำชี้แจงจากผู้แต่งโปรดแสดงความคิดเห็นใต้โพสต์ของพวกเขา
Rachcha

@ ราชาฉันอธิบายได้ดีกว่า หวังว่าคุณจะชอบมันมากกว่านี้
e18r

12
อย่าทำตามคำแนะนำด้านบน DATABASECHANGELOGLOCK จะต้องมีแถวโดยไม่ต้องมีแถวใด ๆ คุณจะได้รับข้อยกเว้น
odedsh

สิ่งนี้ไม่ได้ช่วยฉันลองทำสิ่งนี้แทนที่จะปล่อยตารางหรืออัปเดตสถานะล็อคเป็น 'เท็จ' มันไม่ทำงาน
Aditya T

หากคุณทำตามคำตอบนี้มีโอกาสที่ดีที่สคริปต์ในอนาคตจะไม่ทำงานเนื่องจากคาดว่าจะมีการล็อกอยู่ หากคุณได้ทำสิ่งนี้แล้วคุณสามารถเพิ่มการล็อคที่ว่างเปล่าเพื่อแก้ไขปัญหา INSERT INTO yourdb.DATABASECHANGELOGLOCK VALUES (1, 0, null, null);
Rudi Kershaw

24

ปัญหาคือการนำ buggy ไปใช้ของ SequenceExists ใน Liquibase เนื่องจากชุดการเปลี่ยนแปลงที่มีข้อความเหล่านี้ใช้เวลานานมากและถูกยกเลิกโดยไม่ตั้งใจ จากนั้นลองอีกครั้งเพื่อเรียกใช้งานสคริปต์ liquibase ที่ล็อคไว้

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

Lockdata ถูกเก็บไว้ในตาราง DATABASECHANGELOCK เพื่อกำจัดล็อคคุณเพียงแค่เปลี่ยน 1 เป็น 0 หรือวางตารางนั้นและสร้างใหม่


1
ใน liquibase 3.0.2 (เวอร์ชันที่ฉันใช้) อย่าลบหนึ่งบรรทัดออกจากตารางล็อคหรือคุณจะมีข้อผิดพลาดที่แตกต่างกันเมื่อเรียกใช้ liquibase ในครั้งถัดไปเพราะ liquibase คาดว่าแถวหนึ่งจะอยู่ที่นั่น (หรือ หายไปทั้งตาราง) ตรงตามที่ Peter กล่าวเอาไว้เพียงต้องการเพิ่มข้อมูลนั้นเพราะในรุ่นเก่าดูเหมือนว่าจะทำงานเพื่อลบแถวออกด้วย
Kariem

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 และ liquibase และไม่ต้องการลบสถานะล็อคใน db แต่ละครั้งด้วยตนเอง แต่ฉันไม่เข้าใจว่าคุณฉีด ForceReleaseLockService ไปยัง liquibase อย่างไร ไม่ต้องใส่คำอธิบายประกอบบริการ / ส่วนประกอบในคลาสนี้สปริงนั้นเลือกเป็นถั่วหลักหรือไม่
Andrej Tihonov

1
มันถูกกล่าวถึงในประโยคสุดท้าย: "คลาสจะต้องอยู่ในแพ็คเกจ liquibase.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

ฉันซาบซึ้งว่านี่ไม่ใช่ปัญหาของ OP แต่ฉันพบปัญหานี้เมื่อเร็ว ๆ นี้ด้วยสาเหตุอื่น สำหรับการอ้างอิงฉันใช้ปลั๊กอิน Liquibase Maven (liquibase-maven-plugin: 3.1.1) กับ SQL Server

อย่างไรก็ตามฉันได้คัดลอกและวางคำสั่ง "ใช้" ของ SQL Server ลงในหนึ่งในสคริปต์ของฉันที่เปลี่ยนฐานข้อมูลดังนั้น liquibase จึงทำงานและอัปเดตการDATABASECHANGELOGLOCKรับการล็อคในฐานข้อมูลที่ถูกต้อง แต่จากนั้นสลับฐานข้อมูลเพื่อใช้การเปลี่ยนแปลง ไม่เพียง แต่ฉันจะไม่เห็นการเปลี่ยนแปลงหรือการตรวจสอบ liquibase ของฉันในฐานข้อมูลที่ถูกต้อง แต่แน่นอนเมื่อฉันเรียกใช้ liquibase อีกครั้งมันไม่สามารถรับการล็อคได้เนื่องจากการล็อกถูกปล่อยในฐานข้อมูล "ผิด" และอื่น ๆ ยังคงถูกล็อคในฐานข้อมูล "ถูกต้อง" ฉันคาดว่า liquibase เพื่อตรวจสอบการล็อคยังคงถูกนำไปใช้ก่อนที่จะปล่อยมันและอาจเป็นข้อผิดพลาดใน liquibase (ฉันยังไม่ได้ตรวจสอบ) แต่มันอาจได้รับการแก้ไขในรุ่นต่อมา! ที่กล่าวว่าฉันคิดว่ามันอาจจะเป็นคุณสมบัติ!

ฉันรู้ข้อผิดพลาดเล็กน้อย แต่ฉันยกมันมาที่นี่ในกรณีที่ทุกคนประสบปัญหาเดียวกัน!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.