Differenza tra "lettura confermata" e "lettura ripetibile"


245

Penso che i livelli di isolamento sopra riportati siano così simili. Qualcuno potrebbe descrivere con alcuni esempi interessanti qual è la differenza principale?


3
È necessario espandere la domanda e aggiungere tag per il "livello di isolamento" a cui si fa riferimento (Java, ecc.). "livello di isolamento" è un termine un po 'ambiguo, e ovviamente stai chiedendo una risposta per un ambiente specifico.
Gesù,

Risposte:


564

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.

  • in READ COMMITTED, il secondo SELECT può restituire qualsiasi dato. Una transazione simultanea può aggiornare il record, eliminarlo, inserire nuovi record. La seconda selezione vedrà sempre i nuovi dati.
  • in REPEATABLE READ il secondo SELECT è garantito per visualizzare almeno le righe che sono state restituite dal primo SELECT invariato . Nuove righe possono essere aggiunte da una transazione simultanea in quel minuto, ma le righe esistenti non possono essere eliminate né modificate.
  • sotto SERIALIZABLE legge che la seconda selezione è garantita per vedere esattamente le stesse righe della prima. Nessuna riga può essere modificata, né eliminata, né nuove righe potrebbero essere inserite da una transazione simultanea.

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.Transactionsdell'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:


24
Penso che ci sia un errore sopra per REPEATABLE READ: dici che le righe esistenti non possono essere eliminate o modificate, ma penso che possano essere eliminate o modificate perché la lettura ripetibile legge semplicemente uno "snapshot" non i dati effettivi. Dai documenti dev.mysql.com/doc/refman/5.0/en/… : "Tutte le letture coerenti all'interno della stessa transazione leggono l'istantanea stabilita dalla prima lettura."
Derek Litz,

2
@Derek Litz Ho ragione nel dire che: I dati POSSONO / POTREBBERO essere cambiati da una terza parte, mentre la transazione è in corso, ma le letture vedranno comunque i "vecchi" dati originali come se la modifica non fosse avvenuta posto (l'istantanea).
Programmatore

5
@Cornstalks. Sì, le letture Phantom possono verificarsi da eliminazioni (o inserti). Sì, le letture fantasma possono avvenire in isolamento di lettura ripetibile (solo dagli inserti). No, le letture Phantom dalle eliminazioni non possono avvenire in isolamento di lettura ripetibile. Provalo. Quello che sto dicendo non è contraddetto dalla documentazione che hai citato.
AndyBrown,

4
@Cornstalks NP. L'ho menzionato solo perché non ero sicuro al 100% di me stesso e ho dovuto immergermi in profondità per essere sicuro di chi avesse ragione! E non volevo che i futuri lettori fossero fuorvianti. Mantenendo i commenti, probabilmente è meglio conservare come suggerito. Sono sicuro che chiunque sia interessato a quel livello di dettagli precisi sarà abbastanza particolare da leggere tutti i commenti !!
AndyBrown,

12
Grazie per non aver eliminato i tuoi commenti. La discussione aiuta a collegare più punti.
Josh,

68

Lettura ripetibile

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

Leggi impegnato

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?


Ho provato la lettura ripetibile in SQL Server 2008 con "imposta la lettura ripetibile a livello di isolamento". Ha creato due finestre di query sql. Ma non ha funzionato. Perché?
Aditya Bokade,

1
Perché la seconda sessione1 dovrebbe ancora leggere Aaron? La transazione di session2 non è terminata e confermata? Conosco questo vecchio, ma forse qualcuno può far luce.
Sonny Childs,

9
Penso che la lettura ripetibile bloccherà la seconda sessione fino a quando non viene impegnata la prima sessione. Quindi l'esempio è sbagliato.
Nighon,

4
Nel caso di Lettura ripetibile, quando la sessione 1 legge la riga, inserisce un blocco condiviso, che non consentirebbe alcun blocco esclusivo (alla sessione 2) per l'aggiornamento, quindi i dati non possono essere aggiornati.
Taher,

Penso che il server SQL e MySQL si comportino diversamente quando si tratta di aggiornare le righe condivise tra due transazioni
user2488286

23

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.

  • ReadUncommitted : il processo B è in grado di leggere i dati non impegnati dal processo A e potrebbe vedere righe diverse in base alla scrittura B. Nessun blocco
  • ReadCommitted : Il processo B può leggere SOLO dati impegnati dal processo A e potrebbe vedere righe diverse in base alla sola scrittura COMMITTED B. potremmo chiamarlo Simple Lock?
  • RepeatableLead : il processo B leggerà gli stessi dati (righe) qualunque sia il processo A. Ma il processo A può cambiare altre righe. Blocco a livello di righe
  • Serializzabile : il processo B leggerà le stesse righe di prima e il processo A non può leggere o scrivere nella tabella. Blocco a livello di tabella
  • Istantanea : ogni processo ha una sua copia e ci stanno lavorando. Ognuno ha il suo punto di vista

15

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


13

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.

Leggi impegnato

Lettura ripetibile: in questo livello di isolamento, la Transazione T1 non prenderà in considerazione le modifiche apportate dalla Transazione T2.

inserisci qui la descrizione dell'immagine


1

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)

inserisci qui la descrizione dell'immagine


0

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 .


-1

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.


2
Potresti metterlo nella sezione commenti per ricevere una risposta al risponditore. In questo modo sarà in grado di rispondere alle tue osservazioni e apportare correzioni se necessario.
RBT,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.