Top Up Home HTML2PDF Transaktionen

Anforderungen an Transaktionen (ACID)

Atomarität (Atomicity)

  • Alles oder Nichts
  • Alle Aktionen einer Transaktion werden bestätigt oder keine

Konsistenz (Consistency)

  • Eine Transaktion kann nur bestätigt werden, wenn keine Konsistenbedingungen verletzt sind
  • Ist eigentlich ein Konzept der Anwendung

Isolation (Isolation)

  • Nebenläufige/Parallele Transaktionen beinflussen sich nicht auf unerlaubte Art und Weise
  • Es gibt verschiedene Stufen der Isolation, deren stärkste Serialisierbarkeit ist
  • Stärkere Stufe bedeutet geringere Leistung

Dauerhaftigkeit (Durability)

  • Veränderungen bestätigter Transkationen haben für Folgetransaktionen Bestand
  • Solange bis sie durch weitere Transaktionen bestätigt verändert werden
  • Auch im Falle von Fehlern (z.B. Festplatte defekt)

Mechanismen

Strikte 2-Phasen-Sperren (Strict two-phase locking , 2PL)

  • Lesesperren (Shared Locks , Slocks) vor jedem Lesen
  • Schreibsperren (Exclusive Locks, Xlocks) vor jedem Schreiben
  • Sperren auf existierende Datensätze (Row Level Locks)
  • Sperren basierend auf Prädikate (Predicate Locks) zur Verhinderung von Phantomen
  • Sperren werden bis zum Transkationsende gehalten

Optimistic Concurrency Control (OCC)

  • Lesen und Schreiben ohne Sperren (auf Kopien)
  • Führen der Historie der Lese- und Schreibvorgänge
  • Überprüfung der Historie auf Konflikte vor Commit
  • Abbruch bei Konflikt

Multi-Version Concurrency Control (MVCC) / Snapshot Isolation

  • Keine Lesesperren
  • Änderungen erzeugen neue Versionen
  • Transaktionen sehen Version der letzten bestätigten Änderung, d.h. Lesen und Schreiben stehen nicht in Konflikt
  • Prüfung der Schreibvorgänge, Abbruch bei Konflikt

Optimistische Verfahren auf Anwendungsebene

  • Explizite Versionsfelder
  • Änderung nur, wenn keine Versionsänderung in Datenbank
  • Bsp. OR-Mapper

Isolationsstufen

SQL-Isolationsstufen

  • Read Uncommitted
    • Lesen nichtbestätigter Änderungen möglich
  • Read Committed
    • Lesen nur von bestätigten Änderungen möglich
  • Repetable Read
    • Wiederholtes Lesen in der Transaktion liefert gleichen Wert
  • Serializable
    • Nebenläufige Ausführung von Transkationen muss einer serialisierten Ausführung entsprechen

Produktspezifische Isolationsstufen

  • Snapshot Isolation (PostgreSQL, …)
    • First Committer wins
  • Read Consistency (Oracle)
    • First Updater wins
  • Cursor Stability (DB2, ..)
    • Basiert auf Datenbank-Cursor
    • Sperre bleibt solange bestehen, bis auf den nächsten Datensatz im Cursor weitergeschaltet wird

Anomalie - Dirty Read 1

Before (pid, gehalt): [(100, 40000), (200, 50000)]

T1: select * from personal order by pid
T1: [(100, 40000), (200, 50000)]

          T2: update personal set gehalt=41000 where pid=100
          T2: [(100, 41000), (200, 50000)]

T1: select * from personal order by pid
T1: [(100, 41000), (200, 50000)]
T1: commit and close

          T2: rollback and close

After (pid, gehalt): [(100, 40000), (200, 50000)]

T2 ändert Wert, noch nicht beendet

Wechsel zu T1

T1 liest nichtbestätigten Wert 41000

T2 macht rollback

Anomalie - Dirty Read 2

Before (pid, gehalt): [(100, 40000), (200, 50000)]

T1: update personal set gehalt=41000 where pid=100
T1: [(100, 41000), (200, 50000)]

          T2: select * from personal order by pid
          T2: [(100, 41000), (200, 50000)]
          T2: commit and close

T1: update personal set gehalt=51000 where pid=200
T1: [(100, 41000), (200, 51000)]
T1: commit and close

After (pid, gehalt): [(100, 41000), (200, 51000)]

T2 liest nicht bestätigten Datenbankzustand
[(100, 41000), (200, 50000)]

Ähnlich wie Dirty Read 1, nur kein Rollback

Anomalie - Non Repeatable Read 1

Before (pid, gehalt): [(100, 40000), (200, 50000)]

T1: select * from personal order by pid
T1: [(100, 40000), (200, 50000)]

          T2: update personal set gehalt=41000 where pid=100
          T2: [(100, 41000), (200, 50000)]
          T2: commit and close

T1: select * from personal order by pid
T1: [(100, 41000), (200, 50000)]
T1: commit and close

After (pid, gehalt): [(100, 41000), (200, 50000)]
        

Wiederholtes Lesen des gleichen Datensatzes pid=100 in T1 führt zu unterschiedlichen Werten (40000 und 41000)

Anomalie - Non Repeatable Read 2

Before (pid, gehalt): [(100, 40000), (200, 50000)]

T1: select * from personal where pid=100
T1: [(100, 40000)]

          T2: update personal set gehalt=41000 where pid=100
          T2: update personal set gehalt=51000 where pid=200
          T2: [(100, 41000), (200, 51000)]
          T2: commit and close

T1: select * from personal where pid=200
T1: [(200, 51000)]
T1: commit and close

After (pid, gehalt): [(100, 41000), (200, 51000)]
        

Ähnlich zu Non Repeatble Read 1, nur nicht zweimaliges Lesen des gleichen Datensatzes.

Der Gesamtzustand der Datenbank hat sich beim zweiten Lesen geändert

Anomalie - Lost Update

Before (pid, gehalt): [(100, 40000), (200, 50000)]

T1: select * from personal order by pid
T1: [(100, 40000), (200, 50000)]

          T2: select * from personal order by pid
          T2: [(100, 40000), (200, 50000)]

T1: update personal set gehalt=41000 where pid=100
T1: [(100, 41000), (200, 50000)]
T1: commit and close

          T2: update personal set gehalt=42000 where pid=100
          T2: [(100, 42000), (200, 50000)]
          T2: commit and close

After (pid, gehalt): [(100, 42000), (200, 50000)]
        

T1 und T2 lesen gleichen DB-Zustand

T1 nimmt auf dessen Grundlage Änderungen vor und schreibt

T2 nimmt ebenfalls auf dessen Grundlage Änderungen vor und überschreibt T1

Anomalie - Write Skew

Before (pid, gehalt): [(100, 80), (200, 50)]

T1: [(100, 80), (200, 50)]

          T2: [(100, 80), (200, 50)]

T1: update konto set betrag = betrag -90 where kid=100
T1: [(100, -10), (200, 50)]
T1: commit and close

          T2: update konto set betrag = betrag -50 where kid=200
          T2: [(100, 80), (200, 0)]
          T2: commit and close

After (pid, gehalt): [(100, -10), (200, 0)]

Invariante: Summe auf beiden Konten darf nicht negativ werden.

T1 prüft Summe (130) und stellt fest, dass ein Abheben von 90 von kid=100 ok ist, da Deckung durch kid=200 gegeben.

T2 hebt ebenfalls Geld ab. Dadurch wird die Invariante verletzt.