เดดล็อก: การตรวจจับและการหลีกเลี่ยง
ทำความเข้าใจว่าเดดล็อกเกิดขึ้นได้อย่างไร Postgres ตรวจจับเดดล็อกอย่างไร และออกแบบกฎลำดับการล็อกเพื่อป้องกันเดดล็อก
เดดล็อก: การตรวจจับและการหลีกเลี่ยง เป็นบทเรียน SQL Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน SQL Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส SQL Academy มีบทเรียนทั้งหมด 4 บทเรียน
ภาวะล็อกตายคืออะไร
ธุรกรรมสองรายการต่างถือการล็อกที่อีกฝ่ายต้องการ ทำให้ไม่มีรายการใดดำเนินการต่อได้ ฐานข้อมูลจะตรวจจับวงจรนี้และยกเลิกธุรกรรมหนึ่งรายการ
ภาวะล็อกตายแบบคลาสสิก
ธุรกรรม A ล็อกแถวที่ 1 ส่วนธุรกรรม B ล็อกแถวที่ 2 จากนั้น A ขอแถวที่ 2 และ B ขอแถวที่ 1 ทั้งสองจึงติดอยู่
-- Tx A:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- waiting for B...
-- Tx B:
BEGIN;
UPDATE accounts SET balance = balance - 50 WHERE id = 2;
UPDATE accounts SET balance = balance + 50 WHERE id = 1;
-- waiting for A...
-- ERROR: deadlock detectedPostgreSQL ตรวจจับภาวะล็อกตาย
ทุก ๆ deadlock_timeout (ค่าเริ่มต้น 1 วินาที) PostgreSQL จะตรวจสอบวงจรการล็อก หากพบ จะยกเลิกธุรกรรมหนึ่งรายการพร้อมรหัสข้อผิดพลาด 40P01
ERROR: deadlock detected
DETAIL: Process 1234 waits for ShareLock on transaction 5678 ...กฎการเรียงลำดับการล็อก
วิธีแก้คือ ต้องขอการล็อกตามลำดับเดียวกันเสมอในทุกเส้นทางของโค้ด
-- Always update the lower id first:
UPDATE accounts SET balance = balance - 100 WHERE id = LEAST(:from, :to);
UPDATE accounts SET balance = balance + 100 WHERE id = GREATEST(:from, :to);ภาวะล็อกตายจากแถวที่มีการใช้งานหนาแน่น
การอัปเดตแถวเดิมที่มีการใช้งานหนาแน่นอย่างรวดเร็วมักทำให้เกิดการรอการล็อก ไม่ใช่ภาวะล็อกตาย ให้ใช้การจัดคิว แบ่งแถวที่มีการใช้งานหนาแน่น หรือจัดการอัปเดตให้ทำงานทีละรายการในโค้ดของแอป
FOR UPDATE ล็อกแถวที่อ่าน
ขอการล็อกเพื่อเขียนตั้งแต่เวลาอ่าน เพื่อหลีกเลี่ยงความประหลาดใจในภายหลัง:
BEGIN;
SELECT * FROM accounts WHERE id IN (1, 2) ORDER BY id FOR UPDATE;
-- both rows locked in id order
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;ข้ามแถวที่ถูกล็อก
สำหรับตารางคิว ให้ใช้รูปแบบ "หยิบแถวใดก็ได้ที่พร้อมใช้งาน":
SELECT * FROM jobs
WHERE status = 'pending'
ORDER BY created_at
LIMIT 1
FOR UPDATE SKIP LOCKED;
-- skips rows other workers have lockedNOWAIT
ล้มเหลวทันทีแทนที่จะรอ:
SELECT * FROM accounts WHERE id = 1 FOR UPDATE NOWAIT;
-- ERROR: could not obtain lock on row in relation "accounts"การวินิจฉัยภาวะล็อกตาย
เพิ่มค่า log_lock_waits และเก็บบริบทของภาวะล็อกตายไว้ใน log รายการใน log จะแสดงธุรกรรมทั้งสองรายการและ query ของแต่ละรายการ
วงวนการลองใหม่ในแอปพลิเคชัน
ภาวะล็อกตายสามารถกู้คืนได้ ให้ลองธุรกรรมที่ถูกยกเลิกใหม่:
for (let attempt = 0; attempt < 3; attempt++) {
try {
await runTransaction();
break;
} catch (e) {
if (e.code === '40P01') continue; // deadlock
throw e;
}
}ลดขอบเขตการล็อก
ทำให้ธุรกรรมสั้นลง ทุกแถวที่ถูกแตะต้องจะยังถูกล็อกไว้จนกว่าจะถึง COMMIT อย่าเรียกใช้ HTTP หรือประมวลผลเป็นเวลานานภายในธุรกรรม
สร้างดัชนีให้คีย์ต่างประเทศเพื่อหลีกเลี่ยงการขยายขอบเขตการล็อก
เมื่อคุณลบแถวแม่ ระบบจะตรวจสอบแถวลูกทุกแถว หากไม่มีดัชนี FK จะต้องสแกนทั้งตาราง AND ล็อกแถวด้วย ให้สร้างดัชนีสำหรับคอลัมน์ FK ทุกคอลัมน์
สรุปทบทวน
ภาวะล็อกตายเกิดขึ้นได้ จึงควรออกแบบเพื่อลดโอกาสเกิด
- ขอการล็อกตามลำดับที่สอดคล้องกัน
- ใช้ FOR UPDATE ตั้งแต่เนิ่น ๆ เพื่อประกาศความต้องการ
- ใช้ SKIP LOCKED สำหรับคิว
- ลองใหม่เมื่อเกิดข้อผิดพลาดจากภาวะล็อกตาย (40P01)
- ทำให้ธุรกรรมสั้น
แบบทดสอบสั้น ๆ
หลักการออกแบบใดน่าเชื่อถือที่สุดในการป้องกันภาวะล็อกตาย
คำถามที่พบบ่อย
บทเรียน “เดดล็อก: การตรวจจับและการหลีกเลี่ยง” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “เดดล็อก: การตรวจจับและการหลีกเลี่ยง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส SQL Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส SQL Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “เดดล็อก: การตรวจจับและการหลีกเลี่ยง”
ทำความเข้าใจว่าเดดล็อกเกิดขึ้นได้อย่างไร Postgres ตรวจจับเดดล็อกอย่างไร และออกแบบกฎลำดับการล็อกเพื่อป้องกันเดดล็อก คุณปฏิบัติ SQL Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน SQL Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน SQL Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “เดดล็อก: การตรวจจับและการหลีกเลี่ยง” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน SQL Academy นี้ได้ไหม
ได้ บทเรียน SQL Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- คุณสมบัติ ACID และความผิดปกติ
- ระดับการแยก: READ COMMITTED, REPEATABLE READ, SERIALIZABLE
- เดดล็อก: การตรวจจับและการหลีกเลี่ยง
- การล็อกแบบมองโลกในแง่ดีเทียบกับแบบระมัดระวัง