Nivelul de izolare a tranzacției este o valoare condiționată care determină în ce măsură, ca urmare a executării tranzacțiilor paralele logicSGBD-ului i se permite să primească date inconsistente. Scara nivelurilor de izolare a tranzacțiilor conține un număr de valori clasate de la cel mai mic la cel mai mare; un nivel de izolare mai ridicat corespunde unei mai bune coerențe a datelor, dar utilizarea acestuia poate reduce numărul de tranzacții paralele fizic. În schimb, un nivel mai scăzut de izolare permite mai multe tranzacții paralele, dar reduce acuratețea datelor. Astfel, alegând nivelul de izolare a tranzacțiilor utilizat, dezvoltatorul sistemului informațional, într-o anumită măsură, oferă o alegere între viteza de lucru și asigurarea consistenței garantate a datelor primite de la sistem.
Când tranzacțiile sunt executate în paralel , sunt posibile următoarele probleme:
Luați în considerare situațiile în care pot apărea aceste probleme.
Situația în care, atunci când un bloc de date este schimbat simultan prin diferite tranzacții, una dintre modificări se pierde.
Să presupunem că există două tranzacții care rulează în același timp:
Tranzacția 1 | Tranzacția 2 |
---|---|
UPDATE tbl1 SET f2=f2+20 WHERE f1=1; | UPDATE tbl1 SET f2=f2+25 WHERE f1=1; |
În ambele tranzacții, valoarea câmpului f2 se modifică, la finalizare, valoarea câmpului trebuie mărită cu 45. De fapt, poate apărea următoarea secvență de acțiuni:
Ca urmare, valoarea câmpului f2, la finalizarea ambelor tranzacții, poate crește nu cu 45, ci cu 20 sau 25, adică una dintre tranzacțiile de schimbare a datelor va „dispără”.
Citirea datelor adăugate sau modificate de o tranzacție care nu va reuși ulterior să se comite (rollback).
Să presupunem că avem două tranzacții deschise de aplicații diferite care execută următoarele instrucțiuni SQL:
Tranzacția 1 | Tranzacția 2 |
---|---|
UPDATE tbl1 SET f2=f2+1 WHERE f1=1; | |
SELECT f2 FROM tbl1 WHERE f1=1; | |
ROLLBACK WORK; |
În tranzacția 1, valoarea câmpului f2 este modificată, iar apoi în tranzacția 2, valoarea acestui câmp este selectată. După aceea, tranzacția 1 este anulată. Ca urmare, valoarea primită de a doua tranzacție va diferi de valoarea stocată în baza de date.
Situația în care, la recitirea în cadrul aceleiași tranzacții, datele citite anterior se dovedește a fi modificată.
Să presupunem că există două tranzacții deschise de aplicații diferite în care sunt executate următoarele instrucțiuni SQL :
Tranzacția 1 | Tranzacția 2 |
---|---|
SELECT f2 FROM tbl1 WHERE f1=1; | |
UPDATE tbl1 SET f2=f2+3 WHERE f1=1; | |
COMMIT; | |
SELECT f2 FROM tbl1 WHERE f1=1; |
În tranzacția 2 se selectează valoarea câmpului f2, apoi în tranzacția 1 se modifică valoarea câmpului f2. Dacă încercați din nou să selectați o valoare din câmpul f2 din tranzacția 2, se va obține un rezultat diferit. Această situație este mai ales inacceptabilă atunci când datele sunt citite pentru a le modifica parțial și a le scrie înapoi în baza de date.
Situația în care, în timpul citirii repetate în cadrul aceleiași tranzacții, aceeași selecție dă seturi diferite de rânduri.
Să presupunem că există două tranzacții deschise de aplicații diferite care execută următoarele instrucțiuni SQL:
Tranzacția 1 | Tranzacția 2 |
---|---|
SELECT SUM(f2) FROM tbl1; | |
INSERT INTO tbl1 (f1,f2) VALUES (15,20); | |
COMMIT; | |
SELECT SUM(f2) FROM tbl1; |
Tranzacția 2 execută o instrucțiune SQL care utilizează toate valorile câmpului f2. Apoi, un nou rând este inserat în tranzacția 1, determinând ca reexecuția instrucțiunii SQL din tranzacția 2 să producă un rezultat diferit. Această situație se numește citire fantomă (lectura fantomă). Diferă de citirea nerepetabilă prin faptul că rezultatul accesului repetat la date s-a modificat nu datorită modificării/ștergerii datelor în sine, ci datorită apariției unor date noi (fantomă).
„ Nivelul de izolare a tranzacțiilor ” se referă la gradul de protecție oferit de mecanismele interne ale SGBD (adică, care nu necesită programare specială) față de toate sau unele dintre tipurile de inconsecvențe de date de mai sus care apar în timpul executării paralele a tranzacțiilor. Standardul SQL-92 definește o scară de patru niveluri de izolare: Citire necommitată, Citire comisă, Citire repetabilă, Serializabil. Primul dintre ele este cel mai slab, ultimul este cel mai puternic, fiecare dintre ele ulterioare le include pe toate precedentele.
Cel mai scăzut (primul) nivel de izolare [1] . Dacă mai multe tranzacții paralele încearcă să modifice același rând de tabel, atunci rândul final va avea o valoare determinată de întregul set de tranzacții finalizate cu succes. În acest caz, este posibil să citiți nu numai date inconsistente din punct de vedere logic, ci și date ale căror modificări nu au fost încă înregistrate.
O modalitate tipică de implementare a acestui nivel de izolare este de a bloca datele în timp ce comanda de modificare este în curs de execuție, ceea ce asigură că comenzile de modificare pe aceleași rânduri rulate în paralel sunt de fapt executate secvențial și niciuna dintre modificări nu se pierde. Tranzacțiile numai în citire nu se blochează niciodată sub acest nivel de izolare.
Majoritatea SGBD-urilor industriale, în special Microsoft SQL Server , PostgreSQL și Oracle , utilizează acest nivel în mod implicit. La acest nivel, este asigurată protecție împotriva curentului, citirea „murdară”, totuși, în timpul operațiunii unei tranzacții, alta poate fi finalizată cu succes, iar modificările efectuate de aceasta sunt fixate. Ca rezultat, prima tranzacție va funcționa cu un set de date diferit.
Implementarea unei citiri complete se poate baza pe una dintre două abordări: blocare sau versiune.
Blocarea datelor care pot fi citite și modificabile. Constă în faptul că tranzacția de scriere blochează date mutabile pentru citirea tranzacțiilor care operează la nivelul read committed sau mai mare până la finalizare, prevenind astfel citirea „murdară”, iar datele blocate de tranzacția de citire sunt eliberate imediat după finalizarea Operațiunea SELECT (astfel, o situație de „citire nerepetabilă” poate apărea la un anumit nivel de izolare). Salvarea mai multor versiuni de rânduri care se modifică în paralel. De fiecare dată când se schimbă un rând, SGBD creează o nouă versiune a acestui rând, cu care tranzacția care a schimbat datele continuă să funcționeze, în timp ce orice altă tranzacție „de citire” returnează ultima versiune comisă. Avantajul acestei abordări este că oferă mai multă viteză, deoarece previne blocarea. Cu toate acestea, necesită, în comparație cu primul, o cantitate semnificativ mai mare de RAM, care este cheltuită pentru stocarea versiunilor de rând. În plus, atunci când mai multe tranzacții schimbă datele în paralel, se poate crea o situație în care mai multe tranzacții concurente fac modificări inconsecvente la aceleași date (din moment ce nu există blocări, nimic nu va împiedica acest lucru). Apoi tranzacția care se comite prima își va salva modificările în baza de date principală, iar tranzacțiile paralele rămase vor fi imposibil de comis (deoarece aceasta va duce la pierderea actualizării primei tranzacții). Singurul lucru pe care SGBD-ul îl poate face într-o astfel de situație este să anuleze restul tranzacțiilor și să emită un mesaj de eroare „Înregistrarea a fost deja schimbată”.O metodă specifică de implementare este aleasă de dezvoltatorii SGBD, iar în unele cazuri poate fi personalizată. Deci, în mod implicit, MS SQL folosește blocări, dar (în versiunea 2005 și superioară) când parametrul READ_COMMITTED_SNAPSHOT este setat, baza de date trece la strategia de versiuni, Oracle funcționează inițial numai conform schemei versionate. Informix , puteți preveni conflictele între tranzacțiile de citire și scriere prin setarea parametrului de configurare USELASTCOMMITTED (din versiunea 11.1), care va face ca tranzacția de citire să primească ultimele date comise [2]
Nivelul la care o tranzacție de citire „nu vede” se modifică în datele pe care le-a citit anterior. În același timp, nicio altă tranzacție nu poate modifica datele citite de tranzacția curentă până la încheierea acesteia.
Blocările în modul partajat sunt aplicate tuturor datelor citite de orice instrucțiune dintr-o tranzacție și sunt menținute până la finalizarea tranzacției. Acest lucru împiedică alte tranzacții să modifice rândurile care au fost citite de tranzacția în așteptare. Cu toate acestea, alte tranzacții pot introduce linii noi care corespund condițiilor de căutare pentru instrucțiunile conținute în tranzacția curentă. Când instrucțiunea este repornită de tranzacția curentă, vor fi preluate noi rânduri, rezultând o citire fantomă. Având în vedere că blocările partajate sunt păstrate până la sfârșitul tranzacției, în loc să fie eliberate la sfârșitul fiecărei declarații, gradul de concurență este mai scăzut decât cu nivelul de izolare READ COMMITTED. Prin urmare, în general, nu este recomandat să utilizați în mod inutil acest nivel și niveluri superioare de tranzacție.
Cel mai înalt nivel de izolare; tranzacțiile sunt complet izolate unele de altele, fiecare se execută ca și cum nu ar exista tranzacții paralele. Numai la acest nivel tranzacțiile concurente nu sunt supuse efectului de „citire fantomă”.
SGBD-ul tranzacțional nu acceptă întotdeauna toate cele patru niveluri și poate introduce și altele suplimentare. Există, de asemenea, diverse nuanțe în asigurarea izolației.
Deci, în principiu, Oracle nu acceptă nivelul zero, deoarece implementarea tranzacțiilor exclude „citurile murdare” și în mod oficial nu permite setarea nivelului de citire Repeatable, adică acceptă doar Read committed (în mod implicit) și Serializable. În același timp, la nivelul comenzilor individuale, garantează de fapt repetabilitatea citirii (dacă comanda SELECT din prima tranzacție selectează un set de rânduri din baza de date, iar în acest moment o a doua tranzacție paralelă modifică unele dintre aceste rânduri, atunci setul de rezultate primit de prima tranzacție va conține rânduri neschimbate, ca și cum nu ar exista o a doua tranzacție). Oracle acceptă, de asemenea, așa-numitele tranzacții READ-ONLY, care sunt conforme cu Serializable, dar nu pot schimba datele în sine.
Microsoft SQL Server acceptă toate cele patru niveluri standard de izolare a tranzacțiilor și, în plus, nivelul SNAPSHOT, la care tranzacția vede starea datelor care a fost comisă înainte de a fi începută, precum și modificările făcute de ea însăși, adică se comportă ca și cum a primit lansarea unui instantaneu al datelor bazei de date și lucrul cu acesta. Diferența față de Serialized este că nu sunt folosite blocaje, dar, ca rezultat, efectuarea modificărilor ar putea să nu fie posibilă dacă o tranzacție concomitentă a schimbat aceleași date înainte; în acest caz, a doua tranzacție, atunci când încearcă să COMMIT, va ridica un mesaj de eroare și va fi anulată.
"+" - previne, "-" - nu previne.
nivelul de izolare | lectura fantomă | Lectură care nu se repetă | Lectură „murdară”. | Actualizare pierdută [3] |
---|---|---|---|---|
SERIALIZABIL | + | + | + | + |
CITIRE REPETABILĂ | - | + | + | + |
CITEȘTE ANGAJAT | - | - | + | + |
CITEȘTE NEANGAJAT | - | - | - | + [4] |