Deadlock: rilevamento e prevenzione
Comprenda come si verificano i deadlock, come li rileva Postgres e progetti regole per l’ordine dei lock che li prevengano.
Deadlock: rilevamento e prevenzione è una lezione SQL Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento SQL Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso SQL Academy include 4 lezioni in totale.
Che cos'è un deadlock?
Due transazioni detengono ciascuna un lock richiesto dall'altra: nessuna delle due può procedere. Il database rileva il ciclo e interrompe una delle transazioni.
Un deadlock classico
La transazione A blocca la riga 1, la transazione B blocca la riga 2. A richiede la riga 2, B richiede la riga 1. Il sistema si blocca.
-- 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 rileva i deadlock
Ogni deadlock_timeout (1 secondo per impostazione predefinita), PostgreSQL verifica la presenza di cicli nei lock. Se ne trova uno, interrompe una transazione con il codice di errore 40P01.
ERROR: deadlock detected
DETAIL: Process 1234 waits for ShareLock on transaction 5678 ...Regola sull'ordine dei lock
La soluzione: acquisire sempre i lock nello stesso ordine in tutti i percorsi del codice.
-- 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);Deadlock su righe molto contese
Aggiornamenti rapidi delle stesse righe molto contese causano spesso attese sui lock, non deadlock. Utilizzare una coda, suddividere la riga contesa oppure serializzare gli aggiornamenti nel codice dell'app.
FOR UPDATE blocca le righe lette
Acquisire i lock di scrittura al momento della lettura per evitare sorprese in seguito:
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;Saltare le righe bloccate
Per le tabelle usate come code, pattern per "prelevare una riga qualsiasi disponibile":
SELECT * FROM jobs
WHERE status = 'pending'
ORDER BY created_at
LIMIT 1
FOR UPDATE SKIP LOCKED;
-- skips rows other workers have lockedNOWAIT
Fallire immediatamente invece di attendere:
SELECT * FROM accounts WHERE id = 1 FOR UPDATE NOWAIT;
-- ERROR: could not obtain lock on row in relation "accounts"Diagnosi dei deadlock
Aumentare log_lock_waits e acquisire il contesto del deadlock nel log. La voce di log mostra entrambe le transazioni e le relative query.
Ciclo di retry nell'applicazione
I deadlock sono recuperabili: riprovare la transazione interrotta:
for (let attempt = 0; attempt < 3; attempt++) {
try {
await runTransaction();
break;
} catch (e) {
if (e.code === '40P01') continue; // deadlock
throw e;
}
}Ridurre l'impatto dei lock
Accorciare le transazioni: ogni riga interessata rimane bloccata fino a COMMIT. Non eseguire chiamate HTTP né calcoli lunghi all'interno di una transazione.
Indicizzare le chiavi esterne per evitare l'escalation dei lock
Quando si elimina un elemento padre, viene verificata ogni riga figlia. Senza un indice sulla FK, ciò comporta una scansione completa della tabella E lock sulle righe. Indicizzare ogni colonna FK.
Riepilogo
I deadlock si verificano: progettare il sistema per ridurli al minimo.
- Acquisire i lock in un ordine coerente
- Utilizzare FOR UPDATE in anticipo per dichiarare l'intenzione
- SKIP LOCKED per le code
- Riprovare in caso di errori di deadlock (40P01)
- Mantenere brevi le transazioni
Verifica rapida
Qual è il principio di progettazione più affidabile per prevenire i deadlock?
Domande Frequenti
La lezione «Deadlock: rilevamento e prevenzione» è gratuita?
Sì — il testo completo di «Deadlock: rilevamento e prevenzione» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso SQL Academy, passa a CoddyKit PRO. Il corso SQL Academy include 4 lezioni in totale.
Cosa imparerò in «Deadlock: rilevamento e prevenzione»?
Comprenda come si verificano i deadlock, come li rileva Postgres e progetti regole per l’ordine dei lock che li prevengano. Eserciti SQL Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare SQL Academy?
Non è richiesta alcuna esperienza precedente. SQL Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.
Quanto tempo richiede la lezione «Deadlock: rilevamento e prevenzione»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione SQL Academy?
Sì. Ogni lezione SQL Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Proprietà ACID e anomalie
- Livelli di isolamento: READ COMMITTED, REPEATABLE READ, SERIALIZABLE
- Deadlock: rilevamento e prevenzione
- Locking ottimistico e pessimistico