programowanieInżynier danych

Opisz zasady korzystania z poziomów izolacji transakcji (isolation levels) w SQL oraz jak wybrać odpowiedni poziom izolacji dla aplikacji. Podaj przykłady anomalii dla każdego poziomu.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

Izolacja transakcji wpływa na to, jak jednoczesne transakcje widzą zmiany w sobie nawzajem. To ważna część właściwości ACID. W ANSI SQL istnieją cztery podstawowe poziomy izolacji:

  • READ UNCOMMITTED — Widzi nawet niezatwierdzone zmiany innych transakcji (brudne odczyty, dirty reads).
  • READ COMMITTED — Widzi tylko zatwierdzone zmiany; zapobiega brudnym odczytom, ale dopuszcza niepowtarzalne odczyty (non-repeatable reads).
  • REPEATABLE READ — Te same dane w jednej transakcji są widoczne niezmiennie. Unika brudnych i niepowtarzalnych odczytów, ale mogą występować odczyty fantomowe (phantom reads).
  • SERIALIZABLE — Najbardziej rygorystyczny, transakcje są całkowicie izolowane, jakby były wykonywane kolejno; eliminuje wszystkie rodzaje anomalii.

Wybór poziomu zależy od wymagań aplikacji:

  • Dla raportowania często wystarczający jest poziom REPEATABLE READ lub wyższy;
  • Dla systemów highload optymalnym kompromisem jest READ COMMITTED;
  • Dla finansów — SERIALIZABLE, mimo spadku wydajności.

Przykład:

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; BEGIN; -- Kolejne SELECTy będą widzieć "zamrożone" wartości

Pytanie z podstępem

"Czy poziom REPEATABLE READ gwarantuje ochronę przed odczytami fantomowymi w każdej bazie danych?"

Nie. W PostgreSQL i niektórych innych systemach DB poziom REPEATABLE READ zapobiega tylko brudnym i niepowtarzalnym odczytom, ale niekoniecznie chroni przed odczytami fantomowymi. W MySQL/InnoDB REPEATABLE READ jest zasadniczo równoważny SERIALIZABLE, ale w innych systemach DB — nie.

Przykład:
-- W jednej transakcji wykonujemy SELECT * FROM orders WHERE amount > 100; -- W innej transakcji wstawiono nową wartość z amount > 100 i zatwierdzono -- Pierwsza transakcja przy ponownym SELECT zobaczy "fantomowy" wiersz, jeśli izolacja jest poniżej SERIALIZABLE

Przykłady rzeczywistych błędów wynikających z nieznajomości niuansów tematu


Historia

Usługa finansowa zablokowała tylko READ COMMITTED dla wydajności — użytkownik zobaczył kwotę, którą już zmienił inny proces, pojawiły się rozbieżności w saldzie.


Historia

W systemie rezerwacji hoteli występowały podwójne rezerwacje tego samego pokoju — transakcje nie izolowały wyładowania aktualnych rezerwacji, poziom był READ COMMITTED.


Historia

Przejście z MySQL na PostgreSQL: programista był przyzwyczajony, że REPEATABLE READ chroni przed fantomami, ale po migracji pojawiły się "zawieszone" zamówienia, których nie spodziewano się zobaczyć przy powtarzających się zapytaniach w tej samej transakcji.