Penso che i livelli di isolamento sopra riportati siano così simili. Qualcuno potrebbe descrivere con alcuni esempi interessanti qual è la differenza principale?
Penso che i livelli di isolamento sopra riportati siano così simili. Qualcuno potrebbe descrivere con alcuni esempi interessanti qual è la differenza principale?
Risposte:
Lettura impegnata è un livello di isolamento che garantisce che tutti i dati letti sono stati impegnati al momento della lettura. Limita semplicemente il lettore a vedere qualsiasi lettura intermedia, non impegnata, "sporca". Non promette affatto che se la transazione emette nuovamente la lettura, troverà gli stessi dati, i dati saranno liberi di cambiare dopo essere stati letti.
La lettura ripetibile è un livello di isolamento più elevato, che oltre alle garanzie del livello di lettura impegnato, garantisce anche che i dati letti non possono cambiare , se la transazione legge nuovamente gli stessi dati, troverà i dati letti in precedenza, invariati e disponibile per la lettura.
Il successivo livello di isolamento, serializzabile, offre una garanzia ancora più forte: oltre a tutte le garanzie di lettura ripetibili, garantisce anche che nessun dato nuovo possa essere visto da una lettura successiva.
Supponi di avere una tabella T con una colonna C con una riga al suo interno, supponiamo che abbia il valore "1". E considera di avere un compito semplice come il seguente:
BEGIN TRANSACTION;
SELECT * FROM T;
WAITFOR DELAY '00:01:00'
SELECT * FROM T;
COMMIT;
Questa è una semplice attività che genera due letture dalla tabella T, con un ritardo di 1 minuto tra loro.
Se segui la logica sopra puoi capire rapidamente che le transazioni SERIALIZZABILI, sebbene possano semplificarti la vita, stanno sempre bloccando completamente ogni possibile operazione simultanea, poiché richiedono che nessuno possa modificare, cancellare o inserire alcuna riga. Il livello di isolamento delle transazioni predefinito System.Transactions
dell'ambito .Net è serializzabile e questo di solito spiega le prestazioni abissali che ne risultano.
E infine, c'è anche il livello di isolamento SNAPSHOT. Il livello di isolamento SNAPSHOT offre le stesse garanzie di serializzabili, ma non richiedendo che nessuna transazione simultanea possa modificare i dati. Invece, obbliga ogni lettore a vedere la propria versione del mondo (la sua "istantanea"). Ciò semplifica la programmazione e la scalabilità, poiché non blocca gli aggiornamenti simultanei. Tuttavia, questo vantaggio ha un prezzo: consumo di risorse del server extra.
Letture supplementari:
Lo stato del database viene mantenuto dall'inizio della transazione. Se si recupera un valore in session1, quindi si aggiorna quel valore in session2, recuperandolo di nuovo in session1 si ottengono gli stessi risultati. Le letture sono ripetibili.
session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron
Nel contesto di una transazione, recupererai sempre l'ultimo valore impegnato. Se si recupera un valore in session1, lo si aggiorna in session2, quindi si recupera nuovamente in session1, si otterrà il valore come modificato in session2. Legge l'ultima riga impegnata.
session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;
session1> SELECT firstname FROM names WHERE id = 7;
Bob
Ha senso?
Semplicemente la risposta secondo la mia lettura e comprensione di questo thread e la risposta di @ remus-rusanu si basa su questo semplice scenario:
Esistono due processi A e B. Il processo B sta leggendo la tabella X Il processo A sta scrivendo nella tabella X Il processo B sta leggendo di nuovo la tabella X.
Vecchia domanda che ha già una risposta accettata, ma mi piace pensare a questi due livelli di isolamento in termini di come cambiano il comportamento di blocco in SQL Server. Questo potrebbe essere utile per coloro che eseguono il debug di deadlock come me.
LEGGI IMPEGNATO (impostazione predefinita)
I blocchi condivisi vengono acquisiti in SELECT e quindi rilasciati al termine dell'istruzione SELECT . Ecco come il sistema può garantire che non vi siano letture sporche di dati non impegnati. Altre transazioni possono comunque modificare le righe sottostanti dopo il completamento di SELECT e prima del completamento della transazione.
LETTURA RIPETIBILE
I blocchi condivisi vengono acquisiti in SELECT e quindi rilasciati solo dopo il completamento della transazione . Ecco come il sistema può garantire che i valori letti non cambieranno durante la transazione (perché rimangono bloccati fino al termine della transazione).
Cercando di spiegare questo dubbio con semplici diagrammi.
Leggi impegnato: Qui in questo livello di isolamento, la Transazione T1 leggerà il valore aggiornato della X impegnata dalla Transazione T2.
Lettura ripetibile: in questo livello di isolamento, la Transazione T1 non prenderà in considerazione le modifiche apportate dalla Transazione T2.
Penso che questa immagine possa anche essere utile, mi aiuta come riferimento quando voglio ricordare rapidamente le differenze tra i livelli di isolamento (grazie a kudvenkat su YouTube)
Si noti che, la ripetibilità in lettura ripetibile riguarda una tupla, ma non l'intera tabella. Nei livelli di isolamento ANSC, può verificarsi un'anomalia di lettura fantasma , il che significa che leggere una tabella con la stessa clausola dove due volte può restituire restituire set di risultati diversi. Letteralmente, non è ripetibile .
La mia osservazione sulla soluzione inizialmente accettata.
In RR (mysql predefinito) - Se un tx è aperto e un SELECT è stato attivato, un altro tx NON può eliminare alcuna riga appartenente al set di risultati READ precedente fino a quando non viene eseguito il commit del tx precedente (in realtà l'istruzione delete nel nuovo tx si bloccherà) , tuttavia il prossimo tx può eliminare tutte le righe dalla tabella senza alcun problema. A proposito, un prossimo READ nella precedente tx vedrà ancora i vecchi dati fino a quando non viene eseguito il commit.