ProgrammazioneSviluppatore Backend

Come implementare correttamente la limitazione dell'accesso simultaneo ai dati in SQL (meccanismi di locking, livelli di locking e modalità di gestione)?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Storia della domanda

Con l'emergere di database multiutente è sorta la necessità di limitare la modifica simultanea degli stessi dati. Questo ha portato all'emergere di vari meccanismi di locking (gestione dei locking), che prevenire le modifiche parallele e aiutano a mantenere l'integrità dei dati.

Problema

Senza un controllo dell'accesso, le operazioni simultanee possono portare a danneggiamento o perdita di dati: ad esempio, due transazioni aggiornano simultaneamente una riga e le modifiche di una transazione vengono perse. Locking non sufficientemente rigorosi portano a problemi di concorrenza (race conditions), mentre un eccesso porta a perdite di prestazioni (deadlocks, contention).

Soluzione

Nei moderni DBMS ci sono livelli di locking (row-level, page-level, table-level) e diverse modalità (shared, exclusive, update). Il programmatore può gestirli attraverso impostazioni di isolamento delle transazioni e comandi espliciti di locking (ad esempio, SELECT ... FOR UPDATE).

Esempio di codice:

-- Locking della riga fino al completamento della transazione BEGIN TRANSACTION; SELECT * FROM users WHERE id = 1 FOR UPDATE; UPDATE users SET name = 'New Name' WHERE id = 1; COMMIT;

Caratteristiche chiave:

  • Granularità del locking (riga, pagina, tabella)
  • Locking espliciti e impliciti (tramite transazioni e istruzioni speciali)
  • Influenza del livello di isolamento sullo schema di locking

Domande trabocchetto.

Qual è la differenza tra un locking di lettura (shared lock) e di scrittura (exclusive lock)?

Lo shared lock consente a più transazioni di leggere i dati simultaneamente, ma non di modificarli. L'exclusive lock consente solo a una transazione di modificare i dati, mentre a tutte le altre è vietato l'accesso.


Può un comando SELECT causare un locking?

Di solito SELECT non causa locking, ma se si usa SELECT ... FOR UPDATE o in caso di alto livello di isolamento (ad esempio, SERIALIZABLE), il DBMS può bloccare le righe.

Esempio di codice:

SELECT * FROM products WHERE id = 10 FOR UPDATE;

I locking proteggono sempre dalla "perdita di aggiornamenti"?

No, se il livello di locking o di isolamento è scelto in modo errato, si può ottenere una "lost update" — quando le modifiche di una transazione vengono perse a causa di un'altra. È necessario scegliere con attenzione i meccanismi di gestione della concorrenza.

Errori comuni e anti-pattern

  • Scelta errata del livello di isolamento (troppo basso o troppo alto)
  • Locking non sufficientemente espliciti nelle query critiche
  • Abuso di locking globali (table-level), causando una diminuzione delle prestazioni
  • Mancata liberazione del locking a causa di transazioni incomplete

Esempio della vita reale

Caso negativo

Nel dipartimento di analisi, due programmi aggiornano simultaneamente gli stati degli ordini. Per accelerare, è stato impostato il livello READ UNCOMMITTED per non bloccare le righe. Questo ha portato a conflitti e "perdita" di aggiornamenti, parte dei dati è stata danneggiata.

Pro:

  • Buona velocità all'inizio

Contro:

  • Perdita/danneggiamento di dati chiave
  • Difficoltà di recupero

Caso positivo

Nel dipartimento vendite, i punti critici sono stati protetti con TRANSACTION + SELECT ... FOR UPDATE. È stata separata l'operazione di lettura da quella di aggiornamento a livello di riga.

Pro:

  • Garanzia dell'integrità dei dati
  • Nessuna perdita e duplicazione di modifiche

Contro:

  • In alcuni casi, gli aggiornamenti funzionano leggermente più lentamente (a causa dei locking)