lars
webmobiledatenbankendevopsarchitektur
hello (at) larskoelpin.de

Datenbank Transaktionslevel

October 09, 2022
datenbanken

Änderungen an Daten innerhalb einer Datenbank werden nicht ausschließlich einzeln ausgeführt, sondern können auch von verschiedenen Nutzern parallel ausgeführt werden.

Ein Sicherstellen, dass sich diese parallelen Transaktionen nicht in die quere kommen ist dabei kein triviales Problem. Das Gute dabei: Viele der Probleme sind bereits von Datenbanken behoben. Das Problem: Häufig werden die Probleme von diversen Relationalen-Object-Mappern und Abstraktionen überdeckt. Trotzdem ist es essentiell die Probleme und dazugehören Lösungen zu kennen und zu verstehen.

Konkret gibt es folgend Probleme die bei parallelen Transaktionen auftreten können:

  • Dirty Reads
  • Non-Repeatable Read
  • Phantom Read

Diese können durch die Transaktions-Isolations-Level:

  • READ_UNCOMMITED
  • READ_COMMITED
  • REPEATABLE_READ
  • SERIALIZABLE

auftreten oder eben vermieden werden.

Dirty Reads

Dirty Reads sind wohl das offensichtlichste Problem bei paralleler Transaktionsverarbeitung. Angenommen es existieren wie im Bild 1 zwei parallele Transkationen. Dabei ist der aktuelle Zustand “State” mit i = 0 initialisiert. Beide Transaktionen, T und T2, werden nun parallel verarbeitet.

Bild 1: Dirty Read
Bild 1: Dirty Read

Im Schritt (1) liest T2 dabei den aktuellen Zustand, i = 0 ein. Danach wird im (2) der Wert innerhalb der Transaktion auf i = 1 gesetzt. Die Transaktion wurde noch nicht commited (3), ist aber in diesem Setup direkt von anderen Transaktionen lesbar. Währenddessen beginnt Transaktion T (4) den Wert i = 1 zu lesen, einen nicht commiteten Wert — einen dirty read. Wenn die Transaktion T2 jetzt in Schritt (5) abbricht, basieren alle weiteren Annahmen von T auf falschen, dreckigen, Daten.

Non Repeatable Read

Das zweite Problem beim Lesen von Daten bei parallelen Transaktionen ist der Non Repeatable Read. Dieser beschreibt das Problem, dass während zwei Transaktionen parallel Laufen, die selbe Abfrage unterschiedliche Ergebnisse liefern kann. Im Bild 2 sind dazu zwei Transaktionen, T und T2 zu sehen. Beide Transaktionen lesen zunächst dazu in (1) den Wert i =0. Die Transaktion T2 setzt dabei in (2) und (3) den Wert auf i=1. Obwohl in T in der Zwischenzeit nichts passiert ist, liefert dieselbe query aus (1) in (4) ein anderes Ergebnis als zuvor. Ein Non-Repeatable Read.

Bild 2: Non-Repeatable Read
Bild 2: Non-Repeatable Read

Im Gegensatz zum Dirty Read handelt es sich beim Non-Repeatable Read um das Lesen von commitetter Daten, anstatt temporärer Daten.

Das Problem beim Non Repeatable Read ist also nicht das Lesen von falschen Daten (wie beim Dirty Read) selbst, sondern, dass Lese-Operationen innerhalb der Transaktion nicht deterministisch sind.

Phantom Read

Das letzte lesende Problem bei parallelen Transaktionen ist der Phantom Read. Bei einem Phantom Read sind nicht Änderungen am Datensatz relevant, sondern die Menge der Daten (Insert und Delete).

Bild 3: Phantom Read
Bild 3: Phantom Read

Im Bild 3 sind zwei konkurrierende Transaktionen, T und T2. Die Transaktion T führt in (1) eine Aggregation durch, die die Summe aller Nutzer (Bob und Alice) zurück gibt: 2.

Gleichzeitig fügt die Transaktion T2 in (2) einen neuen Datensatz, “Dave”, hinzu und committet diesen (3). Damit existieren nun 3 Nutzer in dem Datenzustand. Tätigt die Transaktion T nun in (4) genau die gleiche Abfrage wie in (1), ist die Summe 3, statt 2, da eine neue Zeile im Datensatz dazu gekommen ist: Ein Phantom Read.

Isolation-Levels

Diese Probleme sind den Datenbanksystemen natürlich bekannt, weshalb es einen Standard gibt, die Isolationslevel, in denen Transaktionen mehr oder weniger strikt (mit Locking-Mechanismen) ausgeführt werden.

READ_UNCOMMITED ist das am wenigsten geschützte, aber schnellste Transaktionslevel. In diesem Transkationslevel können Dirty Reads, Non-Repeatable Reads und Phantom Reads passieren. Dieses Level braucht dafür auch am wenigsten Koordination zwischen den Transaktionen.

READ_COMMITED ist ein etwas strikteres Level. In diesem Transaktionslevel werden Dirty Reads vermieden.

Im Transaktionslevel REPEATABLE READ, werden zwar Non-Repeatable Reads und Dirty Reads vermieden. Dieses Transaktionslevel sperrt aber nur einzelne Zeilen, weswegen Phantom Reads verhindert werden.

SERIALIZABLE ist das strikteste Level. In diesem Level treten keine der oberen Probleme auf, da diese durch Locking-Regeln seriell ausgeführt werden. Durch das aggressive Locking der Daten, ist dieses Level auch am wenigsten parallelisierbar.

Zusammenfassung

In diesem Beitrag habe ich mir die Probleme angeschaut, die durch Datenbank Transaktionslevel gelöst werden. Dazu habe ich die Probleme von Dirty Reads, Non-Repeatable Reads und Phantom Reads aufgezeigt, sowie diese mit den Transaktionsleveln entgegengestellt. Während geringere Isolationslevel weniger Locking-Mechanismen brauchen, treten bei diesen potentiell auch mehr Probleme innerhalb paralleler Transaktionen auf.