Datenbanktransaktionen, ACID, CAP-Theorem und BASE – IT-Berufe-Podcast #187

Um Datenbanktransaktionen, die ACID-Prinzipien und Alternativen dazu geht es in der einhundertsiebenundachzigsten Episode des IT-Berufe-Podcasts.

TL;DR

An Beispielen aus dem Alltag zeige ich dir, wie Datenbanktransaktionen zusammengehörige SQL-Statements als Einheit ausführen und welche Eigenschaften ACID dafür beschreibt. Du erfährst, wie Isolation parallele Zugriffe absichert, welche Fehler dabei auftreten können und wie du Transaktionen mit SQL oder einem ORM steuerst. Für verteilte Datenbanken kommen das CAP-Theorem und BASE hinzu, die beschreiben, welche Anforderungen an konsistente und verfügbare Daten bestehen. Als IT-Azubi brauchst du dieses Wissen beim Entwickeln von Anwendungen; ACID gehört außerdem zum Prüfungsstoff.

Kapitelmarken

  • [00:00:01] Thema und Bedeutung für die IT-Ausbildung
  • [00:02:58] Was ist eine Datenbanktransaktion?
  • [00:03:28] Beispiel Banküberweisung
  • [00:04:53] Der Begriff Transaktion im Datenbankkontext
  • [00:06:33] Beispiel Blogbeitrag und Tag
  • [00:08:17] Beispiel Bestellung und Bestellposition
  • [00:09:18] Beispiel Versicherungstarif
  • [00:11:28] Die ACID-Prinzipien
  • [00:12:52] Atomicity: Atomarität
  • [00:15:06] Consistency: Konsistenz
  • [00:16:35] Isolation bei parallelen Zugriffen
  • [00:18:58] Durability und Transaktionslogs
  • [00:22:48] Isolationsebenen und Sperren
  • [00:26:24] Serializable
  • [00:29:14] Repeatable Read
  • [00:30:19] Read Committed
  • [00:32:03] Read Uncommitted
  • [00:33:39] Fehler bei parallelen Transaktionen
  • [00:34:12] Dirty Reads
  • [00:36:37] Lost Updates
  • [00:38:20] Non-Repeatable Reads
  • [00:40:05] Phantom Reads
  • [00:42:17] Fehler den Isolationsebenen zuordnen
  • [00:44:36] Transaktionen in SQL und Autocommit
  • [00:46:58] BEGIN TRANSACTION, COMMIT und ROLLBACK
  • [00:48:26] Transaktionen mit ORMs
  • [00:52:13] Jakarta Transactions und Transaction Around
  • [00:56:24] Verteilte Datenbanken und Replikation
  • [01:02:19] Das CAP-Theorem
  • [01:03:32] Konsistenz bei ACID und CAP
  • [01:04:34] Die Eigenschaften von CAP
  • [01:07:17] Die BASE-Prinzipien
  • [01:09:19] Verfügbarkeit am Beispiel eines Streamingdienstes
  • [01:11:35] Basically Available
  • [01:12:15] Soft State
  • [01:12:53] Eventual Consistency
  • [01:15:14] Shownotes und Prüfungsrelevanz
  • [01:16:43] Newsletter zur IT-Ausbildung

Probeabo bei Audible (Affiliate)

Inhalt

Datenbanktransaktionen sollten jedem/jeder ITler:in etwas sagen, da wir fast täglich mit datenbankgestützten Anwendungen arbeiten, egal, ob wir selbst diese Anwendungen programmieren oder „nur“ Abfragen gegen eine Datenbank durchführen.

Was ist eine Datenbanktransaktion?

Eine Transaktion ist eine Menge aus mehreren zusammenhängenden Datenbankoperationen, die gemeinsam als eine Einheit durchgeführt werden müssen.

Beispiele für Datenbanktransaktionen:

  • Banküberweisung von 100 EUR von Konto DE123 auf Konto DE432
    • UPDATE konto SET kontostand = kontostand - 100 WHERE iban = 'DE123';
    • UPDATE konto SET kontostand = kontostand + 100 WHERE iban = 'DE432';
  • Neuen Tag katze zu einem Blog-Post mit ID 123 hinzufügen
    • INSERT INTO tag (id, name) VALUES (1, 'katze');
    • INSERT INTO tag_post (post_id, tag_id) VALUES (123, 1);
  • Neue Bestellung für einen Kunden mit ID 324 erfassen für Artikel 253
    • INSERT INTO bestellung (id, datum, kunde_id) VALUES (123, '2024-04-10', 324);
    • INSERT INTO bestellposition (bestellung_id, artikel_id, menge, preis) VALUES (123, 253, 1, 123.92);
  • Neuen Tarifsatz einer Versicherung anlegen und bisherigen beenden
    • UPDATE tarif SET gueltig_bis='2024-04-10' WHERE id=122;
    • INSERT INTO tarif (id, gueltig_ab, beitrag) VALUES (123, '2024-04-10', 143.23);

Begriffsabgrenzung

Eine Datenbanktransaktion ist nicht zu verwechseln mit einer Transaktion im Geschäftsbetrieb, z.B. einer Überweisung bei einer Bank, dem Kauf eines Autos oder der Buchung eines Fluges.

Die ACID-Prinzipien

Datenbanktransaktion müssen/sollen bestimmten Kriterien genügen, die als ACID-Prinzipien bekannt sind.

  • Atomarität/Atomicity: Alle Datenbankoperationen werden entweder vollständig gemeinsam durchgeführt oder gar nicht. Es kann nicht sein, dass nur einige Operationen durchgeführt werden und andere nicht. Dazu werden die Datenbankoperationen in eine Transaktion „eingeklammert“.
    • Beispiel: Bei der Banküberweisung darf nicht nur Geld abgebucht oder gutgeschrieben werden, sondern beide Buchungen müssen gemeinsam durchgeführt werden.
  • Konsistenz/Consistency: Wenn die Datenbank vor der Transaktion in einem konsistenten Zustand war, dann muss sie es auch nach der Transaktion sein.
    • Beispiel: Bei der Banküberweisung bleibt der Gesamtbetrag an Geld gleich. Es entsteht kein Geld aus dem Nichts und es geht auch kein Geld verloren.
  • Isolation/Isolation: Mehrere Transaktionen dürfen sich nicht gegenseitig beeinflussen. Hierzu folgen weiter unten verschiedene Maßnahmen zur Umsetzung.
    • Beispiel: Bei zwei parallelen Banküberweisungen vom gleichen Konto müssen beide Beträge nacheinander abgebucht werden und nicht nur der der zuletzt durchgeführten Transaktion.
  • Dauerhaftigkeit/Durability: Die Daten müssen nach Abschluss der Transaktion persistent gespeichert sein und z.B. auch einen Systemausfall überstehen. Das wird durch sogenannte Transaktionslogs sichergestellt.
    • Beispiel: Wenn nach dem Abschluss einer Transaktion der Datenbankprozess abstürzt, müssen auch nach dem Neustart der Datenbank die aktualisierten Daten vorhanden sein.

Maßnahmen zur Wahrung der Isolation von Transaktionen

Wenn Transaktionen nicht isoliert voneinander ablaufen, können verschiedene Probleme in der Datenbank auftreten.

  • Dirty Read: Veränderte Daten einer noch offenen Transaktion werden von einer anderen Transaktion gelesen und weisen somit einen „dreckigen“ Zustand auf, weil er noch nicht final ist.
    • Beispiel: Bei einem Ticketkauf geht die zweite Buchung schon vom veränderten Bestand der ersten Transaktion aus.
  • Lost Updates: Wenn zwei Transaktionen gleichzeitig denselben Datensatz verändern, „gewinnt“ die Änderung der zuletzt durchgeführten Transaktion und die der ersten ist verloren.
    • Beispiel: Bei zwei Banküberweisungen wird der Kontostand auf den Ursprungsstand abzgl. der zweiten Überweisung gesetzt, aber ohne die erste Überweisung abzuziehen.
  • Non-Repeatable Read: Wiederholte Lesevorgänge innerhalb einer Transaktion liefern unterschiedliche Ergebnisse.
    • Beispiel: Bei einer Flugbuchung wird geprüft, ob noch ausreichend Plätze frei sind, aber durch eine parallele Buchung wird bei der zweiten Abfrage ein unterschiedliches Ergebnis geliefert.
  • Phantom Read: Während eine Transaktion Datensätze nach einem bestimmten Kriterium liest, werden weitere Datensätze zum gleichen Kriterium hinzugefügt/gelöscht/verändert.
    • Beispiel: Während der Durchschnittsberechnung von Gehältern von Mitarbeiter:innen wird ein neuer Mitarbeiter hinzugefügt, der beim Summieren des Gehalts noch nicht berücksichtigt wird, aber beim Zählen der Datensätze dann schon.

Die Datenbank kann verschiedene Transaktionsisolationsebenen implementieren, um den obigen Problemen entgegenzuwirken. Grundsätzlich werden dabei Sperren verwendet, um die gleichzeitige Verarbeitung der Daten einzuschränken. Es kann dabei eine Lesesperre und/oder eine Schreibsperre gesetzt werden, wodurch das gleichzeitige Lesen bzw. Schreiben eingeschränkt wird.

  • Read Uncommitted: Es werden keine Sperren verwenden. Quasi kein Schutz vor obigen Problemen. Vergleichbar mit NO ACTION bei referenzieller Integrität.
  • Read Committed: Für die gesamte Transaktion werden Schreibsperren auf alle beteiligten Objekte gesetzt, die verändert werden sollen. Lesesperren werden aber nur kurzzeitig gesetzt. Es können Non-Repeatable Read und Phantom Read auftreten.
  • Repeatable Read: Es werden für die gesamte Transaktion Lese- und Schreibsperren auf alle beteiligten Objekte gesetzt. Nur Phantom Reads können noch auftreten (weil dabei zwei lesende Operationen mit unterschiedlichen Kriterien durchgeführt werden).
  • Serializable: Die Datenbank verhält sich so, als würden die Transaktionen komplett separiert nacheinander („seriell“) durchgeführt. Dabei kann keines der obigen Probleme mehr auftreten, aber Transaktionen müssen ggfs. abgebrochen werden. Starten z.B. zwei Flugbuchungen für zwei Sitzplätze parallel auf dem Sitzplatzbestand von 2, wird die erste Transaktion den Bestand auf 0 reduzieren und die zweite Transaktion (die „gewartet“ hat) muss abbrechen, weil die Sitzplätze nun nicht mehr ausreichen.

Umsetzung in SQL

Mit der Transaction Control Language (TCL) gibt es eine eigene Familie an SQL-Befehlen, die sich nur um die Transaktionssteuerung kümmert. Hiermit können Datenbankoperationen zu einer Transaktion zusammengefasst werden.

  • BEGIN TRANSACTION: Startet eine Datenbanktransaktion.
  • COMMIT: Beendet eine Datenbanktransaktion und schreibt die Änderungen fest.
  • ROLLBACK: Rollt eine Datenbanktransaktion zurück und verwirft alle Änderungen.

In vielen Datenbanken muss man nicht explizit Transaktionen starten und beenden. Sie verwenden ein sogenanntes Auto-Commit. Dabei wird jedes Statement in einer eigenen Transaktion durchgeführt.

Umsetzung in ORMs

Brauche ich als Softwareentwickler:in überhaupt Wissen über Datenbanktransaktionen? In modernen Entwicklungsprojekten werden doch sowieso objektrelationale Mapper (ORM) verwendet. Doch auch diese ORMs können natürlich nicht zaubern, sondern verwenden unter der Haube die normalen Datenbankoperationen. Daher ist auch bei Verwendung eines ORMs wichtig zu wissen, welche Operationen in einer gemeinsamen Transaktion durchgeführt werden müssen.

Dafür bieten viele ORMs entsprechende Befehle an. Jakarta EE hat sogar einen eigenen Standard dafür: Jakarta Transactions (JTA). Dort wird z.B. Annotation @Transactional verwendet. Diese wird an eine Java-Methode geschrieben, die dann automatisch innerhalb einer Datenbanktransaktion ausgeführt wird. Im Fall einer aufgetretenen Exception wird dabei dann automatisch ein Rollback durchgeführt.

CAP und BASE

Transaktionen nach den ACID-Prinzipien sind ein wichtiger Bestandteil vieler Datenbanksysteme. Sobald die Datenbank jedoch auf mehrere Knoten verteilt wird, können Transaktionen zu einem Problem werden. Das sogenannte CAP-Theorem besagt, dass es in einem verteilten System nicht möglich ist, alle drei Eigenschaften Konsistenz, Verfügbarkeit und Ausfalltoleranz gleichzeitig zu garantieren.

  • Konsistenz (Consistency): Die Konsistenz meint in diesem Kontext den einheitlichen Datenstand über alle Datenbankknoten hinweg (und nicht die Konsistenz vor/nach einer Transaktion). Egal, welcher Knoten abgefragt wird, es werden immer die gleichen Daten zurückgegeben.
  • Verfügbarkeit (Availability): Die Datenbank antwortet in akzeptabler Zeit auf alle Anfragen. Dabei kann es jedoch sein, dass nicht immer die aktuellsten Daten geliefert werden.
  • Partitionstoleranz (Partition tolerance): Die Datenbank arbeitet auch weiter, wenn einzelne Knoten ausfallen.

Angenommen, die verteilte Datenbank soll zu jedem Zeitpunkt in einem konsistenten Zustand sein (also alle Informationen auf allen Knoten sollen identisch sein), dann führt ein Ausfall eines Knoten automatisch dazu, dass eine Transaktion fehlschlagen muss, da der ausgefallene Knoten nicht sofort aktualisiert werden kann. Die Konsistenz wäre dann zwar gewährleistet, aber die Partitionstoleranz nicht.

Da heutzutage viele Anwendungen tatsächlich mit verteilten Datenbanken arbeiten, wurde mit BASE ein Gegenentwurf zu ACID geschaffen. Das Wort ist etwas konstruiert, um das Gegenstück zu ACID zu bilden. Aus der Chemie kennen wir den Unterschied zwischen Säure („acid“) und Lauge („base“). Im Kern stellt ACID die Konsistenz eines Systems sicher, während BASE die Verfügbarkeit in den Vordergrund stellt.

  • Basically Available: Die Datenbank ist grundsätzlich für alle Benutzer jederzeit erreichbar (hohe Verfügbarkeit).
  • Soft state: Daten können sich im Laufe der Zeit verändern und temporäre („weiche“) Zustände annehmen, wenn mehrere Änderungen parallel durchgeführt werden.
  • Eventual consistency: Irgendwann einmal werden die Daten in der Datenbank einen konsistenten Zustand erreichen. Bis dahin können Anfragen unterschiedliche Ergebnisse produzieren.
    • Vorsicht „false friend“: „eventually“ heißt auf Deutsch „schlussendlich“ und nicht „eventuell“. Es wird also immer Konsistenz erreicht, nur eben nicht unmittelbar sofort.

Literaturempfehlungen

Sascha Kersken - IT-Handbuch für Fachinformatiker: Für Fachinformatiker der Bereiche Anwendungsentwicklung und Systemintegration. Inkl. Prüfungsfragen und Praxisübungen (Affiliate)*

In Kapitel 13 gibt es eine gute und kurze Einführung in das Thema Datenbanken inkl. Transaktionen. Ich habe das Kapitel auch schon im Buchclub besprochen: Buchclub: Handbuch für Fachinformatiker (Teil 11: Datenbanken)

Links

Zusammenfassung

Datenbanktransaktionen im IT-Alltag

Wenn du als Fachinformatiker:in Anwendungsentwicklung Daten speicherst, musst du festlegen, welche Schritte fachlich zusammengehören. Das betrifft selbst geschriebene SQL-Statements ebenso wie Anwendungen, die über einen objektrelationalen Mapper auf die Datenbank zugreifen. Für deine AP2, dein Abschlussprojekt und das Fachgespräch gehört das Thema zum relevanten Wissen.

Zusammengehörige Statements als Einheit ausführen

Eine Datenbanktransaktion fasst zusammengehörige Datenbankoperationen zu einer Einheit zusammen. Darin können SELECT, INSERT, UPDATE und DELETE vorkommen. Auch das Lesen von Daten kann Teil einer Transaktion sein, etwa wenn du eine ID für einen späteren Schreibzugriff ermittelst.

An diesen Beispielen zeige ich dir, welche Schritte gemeinsam ausgeführt werden müssen:

  • Geld überweisen: Für 100 Euro zwischen zwei Konten brauchst du zwei Updates. Beim einen Konto sinkt der Kontostand um 100 Euro, beim anderen steigt er entsprechend. Ein Abbruch zwischen den Updates würde die gesamte Geldmenge verändern.
  • Einen Blogbeitrag mit einem neuen Tag versehen: Du legst den Tag an und verknüpfst ihn anschließend mit dem Beitrag. Bei einer M:N-Beziehung entsteht diese Verknüpfung in einer Zuordnungstabelle wie TagPost.
  • Eine Bestellung erfassen: Zur Bestellung gehört mindestens eine Bestellposition, die den bestellten Artikel referenziert. Beide Datensätze müssen gemeinsam entstehen.
  • Einen Versicherungstarif ändern: Du setzt das Enddatum des bisherigen Tarifs und legst den folgenden Tarif mit seinem neuen Beitrag an. Dadurch schließen die gültigen Zeiträume aneinander an.

Der Begriff "Transaktion" kommt auch im Geschäftsalltag vor, etwa für einen Autokauf oder eine Überweisung. Im Datenbankkontext bezeichnet er die technische Einheit aus zusammengehörigen Statements.

Die ACID-Prinzipien

ACID beschreibt vier Eigenschaften, die eine Datenbank für ihre Transaktionen gewährleisten soll.

A: Atomicity, Atomarität

Alle Operationen innerhalb der Transaktion bilden eine unteilbare Einheit. Die Datenbank übernimmt sie vollständig. Falls die Transaktion scheitert, werden ihre Änderungen zurückgenommen.

Du kannst dir dafür eine Transaktionsklammer vorstellen, die vom Start bis zum Ende reicht und alle enthaltenen Statements zusammenfasst.

C: Consistency, Konsistenz

Wenn die Datenbank vor der Transaktion konsistent war, muss sie anschließend wieder konsistent sein. Bei einer Überweisung bleibt beispielsweise die Summe der Beträge auf den beteiligten Konten erhalten.

Diese Eigenschaft setzt einen konsistenten Ausgangszustand voraus. Bereits vorhandene fehlerhafte Daten brauchen eigene Maßnahmen, um sie zu bereinigen.

I: Isolation

Bei parallelen Zugriffen müssen Transaktionen voneinander isoliert ablaufen. Sonst kann eine Transaktion mit Zwischenständen einer anderen arbeiten oder deren Änderungen überschreiben.

Eine einfache Lösung besteht darin, Transaktionen nacheinander auszuführen. Bei vielen gleichzeitigen Zugriffen entstehen dabei Wartezeiten. Datenbanken bieten deshalb verschiedene Isolationsebenen an.

D: Durability, Dauerhaftigkeit

Sobald eine Transaktion erfolgreich abgeschlossen wurde, müssen ihre Änderungen dauerhaft gespeichert sein und einen Systemausfall überstehen. Daten im flüchtigen Arbeitsspeicher gehen bei einem Stromausfall verloren.

Viele Datenbanken schreiben Änderungen deshalb in Transaktionslogs auf einen dauerhaften Datenträger. Nach einem Absturz können sie anhand dieser Einträge Änderungen nachtragen, die noch in die eigentliche Datenhaltung übernommen werden müssen.

Isolationsebenen und Sperren

Für die Isolation arbeite ich hier mit einem vereinfachten Modell aus Lese- und Schreibsperren. Solche Locks können einzelne Datensätze oder ganze Tabellen betreffen. Wie fein die Datenbank sperrt, beeinflusst, welche Zugriffe gleichzeitig möglich bleiben.

Wenn zwei Mitarbeiter:innen unterschiedliche Tabellen bearbeiten, können ihre Transaktionen parallel laufen. Beim gleichzeitigen Bearbeiten desselben Datensatzes muss die Datenbank den Zugriff koordinieren.

Die vier vorgestellten Isolationsebenen lassen sich in diesem vereinfachten Sperrmodell so beschreiben:

| Ebene | Beschreibung |
| — | — |
| Read Uncommitted | Es werden keine Sperren eingesetzt, um Transaktionen voneinander zu isolieren. |
| Read Committed | Für die beteiligten Objekte werden Schreibsperren während der Transaktion gehalten. Lesende Zugriffe bleiben möglich. |
| Repeatable Read | Lese- und Schreibsperren schützen die beteiligten Objekte während der Transaktion. Wiederholte gleiche Abfragen liefern dasselbe Ergebnis. |
| Serializable | Transaktionen werden so behandelt, als würden sie vollständig nacheinander ablaufen. |

Welche Ebenen eine Datenbank anbietet und welche du auswählen kannst, hängt vom jeweiligen System ab. Umfangreiche Sperren können Wartezeiten verursachen. Da Daten häufig gelesen werden, wirkt sich das Sperren lesender Zugriffe auf viele Operationen aus.

Fehler bei parallelen Transaktionen

  • Dirty Read: Eine Transaktion liest Änderungen einer anderen, die noch läuft. Beim Ticketverkauf könnte sie dadurch einen erhöhten Ticketbestand sehen, obwohl die zugehörige Stornierung noch offen ist.
  • Lost Update: Zwei Transaktionen lesen denselben Ausgangswert und überschreiben beim Speichern gegenseitig ihre Änderungen. Bei einem Kontostand von 1.000 Euro berechnet die erste nach einer Abbuchung von 100 Euro einen Stand von 900 Euro. Die zweite berechnet auf Grundlage der ursprünglichen 1.000 Euro nach einer Abbuchung von 50 Euro einen Stand von 950 Euro. Speichert sie zuletzt, geht die erste Abbuchung verloren.
  • Non-Repeatable Read: Eine Transaktion liest dieselben Daten mehrfach und erhält unterschiedliche Ergebnisse, weil eine andere Transaktion sie zwischenzeitlich geändert hat. Das kann etwa beim Prüfen freier Flugplätze passieren.
  • Phantom Read: Während einer Transaktion verändert sich die Menge der Datensätze, auf die ihre Abfragen zugreifen. Wenn du zunächst die Gehälter von 27 Mitarbeiter:innen summierst und nach einem parallel eingefügten Datensatz 28 Mitarbeiter:innen zählst, berechnest du daraus einen falschen Durchschnitt.

Die vorgestellte Zuordnung der Fehler zu den Isolationsebenen lautet:

| Ebene | Mögliche Fehler |
| — | — |
| Read Uncommitted | Dirty Reads, Lost Updates, Non-Repeatable Reads und Phantom Reads |
| Read Committed | Non-Repeatable Reads und Phantom Reads |
| Repeatable Read | Phantom Reads |
| Serializable | Die vier genannten Fehler sind ausgeschlossen. |

Transaktionen mit SQL steuern

SQL enthält mit der Transaction Control Language, TCL, eine eigene Gruppe von Befehlen für Transaktionen:

  • Mit BEGIN TRANSACTION startest du eine Transaktion und führst anschließend die zusammengehörigen Statements aus.
  • COMMIT beendet die Transaktion und schreibt ihre Änderungen dauerhaft fest.
  • Durch ROLLBACK nimmst du die Änderungen bis zum Beginn der Transaktion zurück.

Bei Datenbanken wie MySQL oder MariaDB ist häufig Autocommit eingeschaltet. Dann wird jedes einzelne Statement automatisch als eigene Transaktion abgeschlossen. Für mehrere fachlich zusammengehörige Statements musst du eine gemeinsame Transaktion ausdrücklich steuern und das Autocommit-Verhalten berücksichtigen.

In der Dokumentation deiner Datenbank findest du, wie sie Transaktionen standardmäßig behandelt und wie du dieses Verhalten konfigurierst.

Transaktionen beim Entwickeln mit ORMs

Ich arbeite selbst mit ORMs, die Objekte auf relationale Tabellen abbilden und viele Aufgaben beim Datenbankzugriff übernehmen. Beispiele sind Hibernate für Java und das Entity Framework für .NET.

Als Entwickler:in legst du weiterhin fest, welche Änderungen fachlich zu einer Transaktion gehören. Dazu zählt auch, was bei einem Fehler passieren soll. Wenn während mehrerer Schreibzugriffe etwa ein Timeout oder ein Netzwerkproblem auftritt, muss die Transaktion die bereits ausgeführten Änderungen zurückrollen können.

Jakarta Transactions und Transaction Around

Im Java-Umfeld gibt es mit Jakarta Transactions, JTA, eine eigene Spezifikation für Transaktionen. Eine Methode kann beispielsweise mit @Transactional gekennzeichnet werden.

Beim vorgestellten Transaction-Around-Pattern legt das Framework eine Transaktionsklammer um den Methodenaufruf. Vorher startet es die Transaktion. Nach erfolgreichem Ausführen folgt der Abschluss; im beschriebenen Fehlerfall übernimmt das Framework den Rollback.

Dadurch entfällt wiederkehrender Code für die Transaktionssteuerung. Du entscheidest, welche Methode diese Klammer braucht, und prüfst in der Dokumentation deines Frameworks, wie es Transaktionen behandelt.

Verteilte Datenbanken

Wenn Datenbankknoten beispielsweise in Amerika und Europa stehen, müssen sie Änderungen untereinander abgleichen. Dieser Vorgang heißt Replikation.

Soll nach einem Schreibzugriff überall derselbe Datenstand vorliegen, muss das System auf den Abgleich warten. Lange Netzwerkwege verzögern dadurch das Speichern. Ein unerreichbarer Knoten erschwert zusätzlich, den gemeinsamen Stand sicherzustellen.

Aus meiner Arbeit in einer Versicherung kenne ich auch Anwendungen, für die eine zentrale Datenbank ausreicht. Weltweit verteilte Kund:innen oder eine Cloud-Infrastruktur können andere Anforderungen mit sich bringen.

Das CAP-Theorem

CAP beschreibt Anforderungen an verteilte Systeme:

  • Consistency: Die Knoten haben einen einheitlichen Datenstand, sodass eine Abfrage an jedem Knoten dieselbe Antwort liefert.
  • Availability: Das System bleibt erreichbar und beantwortet Anfragen.
  • Partition Tolerance: Das System arbeitet weiter, wenn Teile davon wegen eines Ausfalls oder eines Netzwerkproblems unerreichbar sind.

In der vereinfachten Darstellung des Theorems können zwei dieser Eigenschaften gleichzeitig gewährleistet werden. Alle drei zusammen lassen sich dabei nicht vollständig erfüllen.

Wenn ein Update einen Knoten wegen eines Netzwerkproblems verfehlt, entsteht beispielsweise ein Problem für den einheitlichen Datenstand. Ein System, das diesen Stand voraussetzt, muss den Schreibzugriff entsprechend behandeln und kann dadurch seine Verfügbarkeit einschränken.

Bei ACID beschreibt Consistency den gültigen Zustand der Datenbank vor und nach einer Transaktion. Im CAP-Kontext bezieht sich der Begriff auf den einheitlichen Datenstand über mehrere Knoten hinweg.

Die BASE-Prinzipien

BASE beschreibt ein Modell für verteilte Datenbanken, bei dem die Verfügbarkeit im Vordergrund steht. Die vier Buchstaben bilden drei Begriffe:

Basically Available

Die Datenbank ist grundsätzlich erreichbar und beantwortet Anfragen. Die gelieferten Daten können einen älteren Stand haben.

Soft State

Während Änderungen zwischen den Knoten abgeglichen werden, können temporäre Zustände entstehen. Je nach abgefragtem Knoten kann eine Antwort deshalb unterschiedlich ausfallen.

Eventual Consistency

Die Daten werden schließlich zu einem konsistenten Stand zusammengeführt. Dieser Abgleich kann Zeit brauchen, etwa wenn ein Server vorübergehend ausgefallen ist.

Das englische eventual bedeutet hier "schlussendlich". Ein gemeinsamer Datenstand bleibt das Ziel.

Als Beispiel dient ein Streamingdienst: Wenn du einen Film startest, brauchst du einen erreichbaren Dienst. Zeitweise unterschiedliche Filmempfehlungen an verschiedenen Standorten sind bei diesem Anwendungsfall akzeptabel.

Prüfung und weiterführende Inhalte

ACID wurde bereits ausdrücklich in schriftlichen Prüfungen abgefragt. Für CAP und BASE halte ich Prüfungsfragen ebenfalls für möglich, weil NoSQL-Datenbanken und verteilte Anwendungen verbreitet sind. Die Details zu Isolationsebenen und den zugehörigen Fehlern schätze ich als Wissen für die Praxis ein; eine Prüfungsfrage dazu erwarte ich weniger.

Meine Beispiele und ergänzende Links findest du in den Shownotes zur Episode 187. Über meinen kostenfreien Newsletter erhältst du ungefähr einmal pro Woche Inhalte passend zu deinem Ausbildungsstand, von deinen Rechten und Pflichten bis zum Abschlussprojekt.

Transkription der gesamten Episode

Automatisch erzeugte Transkription der Episode

[0:01] Herzlich willkommen zum IT-Berufe-Podcast, dem Podcast rund um die Ausbildung in den IT-Berufen.

[0:07] In dieser Episode geht es um Datenbanktransaktionen, die ACID-Prinzipien, das CAP-Theorem und BASE.

[0:15] Oh, let's go, würde ich sagen. Viel Spaß!

[0:20] Hallo und herzlich willkommen zur 187. Episode des IT-Berufe-Podcasts.

[0:25] Mein Name ist Stefan Macke und heute geht es um ein Thema, das uns alle betrifft in der IT, und zwar um Datenbanken.

[0:32] Jeder von uns in der IT hat wahrscheinlich täglich oder mehrfach die Woche oder auch manchmal seltener, aber relativ häufig, mit Datenbanken zu tun.

[0:40] Und Daten in der Datenbank sollten gespeichert werden, wenn ich die da drin verändere oder einfüge.

[0:45] Und dafür brauchen wir Datenbanktransaktionen.

[0:48] Und das ist ein wichtiges Thema, was uns in vielen Programmen beschäftigt.

[0:53] Wenn wir selber Software entwickeln zum Beispiel, müssen wir Transaktionssteuerung machen.

[0:56] Aber auch wenn wir simple Abfragen gegen die Datenbank abschießen, zum Beispiel mit SQL, muss ich mich mit Transaktionen auskennen.

[1:01] Eventuell die starten, stoppen, beenden, zurückrollen, was auch immer man damit halt so machen kann.

[1:05] Und deswegen dachte ich mir, ich mache mal eine Episode dazu.

[1:08] Das ist auch insbesondere für die AP2, für Anwendungsentwickler natürlich interessant, gerade auch für das Projekt und für die Fachgespräche.

[1:15] Aber grundsätzlich finde ich Standardwissen, was eigentlich jeder ITler kennen sollte, weil wir alle irgendwie mal mit Datenbanken arbeiten.

[1:21] Und ob wir sie jetzt nur abfragen oder händisch irgendwie befüllen mit SQL-Offer-Kommando-Zeile oder eine Applikation drumherum bauen, ganz egal.

[1:28] Und übrigens auch, da kommen wir extra in einem kleinen Unterkapitel hier heute dazu, wenn ich nur programmiere, nur in Anführungszeichen und zum Beispiel objektrelationale Mapper benutze, muss ich mich trotzdem mit Transaktionen auseinandersetzen.

[1:39] Also ich komme nicht drumherum und das ist ein ganz wichtiges Konzept, damit die Daten in der Datenbank auch Konsistenz bleiben unter anderem.

[1:47] Und darüber wollen wir heute mal sprechen.

[1:49] Ich habe einiges mitgebracht zu dem Thema und ich habe das heute so ein bisschen mal untergliedert.

[1:53] Nummer eins, was ist überhaupt eine Datenbanktransaktion, worum geht es da?

[1:57] Ich habe auch ein paar Beispiele mitgebracht, dass man sich das ein bisschen besser vorstellen kann.

[2:00] Und dann gehen wir vor allem die ACID-Prinzipien durch.

[2:03] Das ist feinstes Prüfungswissen, kann ich sagen, ist aber auch für die Praxis relevant, um nochmal erklären zu können, was eine Transaktion eigentlich ist und was sie so für Eigenschaften haben muss.

[2:12] Dann gibt es verschiedene Maßnahmen, wie man die Isolation von Transaktionen in der Datenbank gewährleisten kann.

[2:18] Da kommen wir dann nochmal drauf, nachdem wir uns angeguckt haben, was Isolation überhaupt ist und wo das alles herkommt.

[2:22] Da habe ich auch ein bisschen was mitgebracht.

[2:24] Dann konkret, wie setzt man das in SQL um?

[2:26] Also welche Statements gibt es in SQL, um Transaktionen überhaupt zu steuern?

[2:30] Und dann gehen wir noch kurz auf ORMs ein, Objekt-Relationen-Mapper, wie ich gerade schon gesagt habe.

[2:34] Und ganz am Ende konzentrieren wir uns dann nochmal auf Sachen, die quasi das Gegenteil von ACID darstellen, nämlich Datenbanken, die nicht transaktional arbeiten.

[2:42] Und da gibt es das sogenannte CAP-Theorem und die BASE-Prinzipien, die werden wir uns dann auch einmal anschauen.

[2:48] Dann sind wir durch heute.

[2:49] Könnte etwas länger werden, deswegen würde ich sagen, ich lege direkt mal los und wir starten mit der Frage, was ist überhaupt eine Datenbanktransaktion?

[2:58] So, diese Frage lässt sich relativ einfach beantworten.

[3:01] Das ist einfach eine Menge an zusammenhängenden oder zusammengehörigen Datenbank-Operationen.

[3:07] Also zum Beispiel wie ein SELECT etwas lesen oder ein INSERT, ein UPDATE, ein DELETE.

[3:12] Irgendetwas, was ich mit der Datenbank mache.

[3:14] Meistens geht es darum, Daten zu verändern oder einzutragen.

[3:17] Das ist oft der Fall, aber grundsätzlich ist es erstmal egal.

[3:20] Es sind einfach mehrere zusammenhängende Operationen gegen die Datenbank, die als Einheit quasi durchgeführt werden.

[3:27] Darum geht es.

[3:28] Und ich habe mal ein Beispiel mitgebracht oder das Lieblingsbeispiel, was oft benutzt wird, ist zum Beispiel die Überweisung vom Bankkonto von einem Konto auf das andere Konto bei einer Bank.

[3:38] Was muss da passieren?

[3:39] Stellen wir uns vor, wir haben so eine Tabelle KONTO, wo dann irgendwie der Kontostand drauf ist und das Konto wird identifiziert über eine IBAN.

[3:47] Der Einfachheit halber machen wir mal eine kurze IBAN und keine richtige, sowas wie 1, 2, 3 und 4, 3, 2 oder so.

[3:52] Und wenn ich jetzt zwei Konten habe, meinetwegen in der gleichen Tabelle KONTO und da steht einfach nur der Kontostand drin und die IBAN, dann müsste ich, um Geld von einem Konto zum anderen zu übertragen, zwei UPDATES machen.

[4:04] Angenommen, ich will 100 Euro überweisen, dann muss ich ein UPDATE machen, um den Kontostand von dem Konto, von dem ich überweise, um 100 Euro zu verringern.

[4:12] Und dann muss ich auch noch ein zweites UPDATE machen, um das Konto, wo das Geld hinüberwiesen wird, um 100 zu erhöhen, logischerweise.

[4:19] Und diese beiden Aktionen gegen die Datenbank sollten bitte zusammen durchgeführt werden.

[4:24] Denn wenn ich mittendrin aufhöre oder die Datenbank abbricht oder sonst irgendwas, dann ist das Geld vielleicht abgebucht, aber noch nicht wieder drauf gebucht.

[4:30] Das heißt, ich habe auf einmal Geld verloren oder umgekehrt, wenn ich erst das Erhöhen mache und dann das Verringern, dann habe ich halt Geld aus dem Nichts erscheinen lassen, weil auf dem anderen Konto nichts abgebucht wurde.

[4:40] Also das darf nicht passieren. Deswegen sollten wir diese beiden UPDATE-Statements immer nur gemeinsam durchführen und nicht nur die Hälfte oder mittendrin abbrechen oder sowas.

[4:48] Das leuchtet, glaube ich, oder leuchtet nicht leuchtet, das leuchtet, glaube ich, ein.

[4:53] Das ist ein schönes Beispiel dafür, ist leider auch gleichzeitig ein nicht ganz so gutes Beispiel, weil diese Überweisung bei der Bank wird auch oft im Alltag, wenn ich nichts mit IT zu tun habe, als Transaktion bezeichnet.

[5:06] Und diesen kleinen Unterpunkt, den ziehe ich mal kurz vor, denn das ist hier nicht gemeint.

[5:10] Die Begriffsabgrenzung ist hier ganz wichtig. Im Kontext von Datenbanken haben Transaktionen eine ganz besondere Definition, die wir uns ja heute hier auch angucken.

[5:19] Ganz allgemein ist der Begriff Transaktion aber anders definiert.

[5:24] Er hat erstmal nichts mit Datenbanken zu tun, sondern meistens geht es darum, dass ich im Geschäftsbetrieb eine Transaktion durchführe, zum Beispiel eine Überweisung.

[5:32] Oder ich kaufe ein Auto, das ist auch eine Transaktion.

[5:35] Oder ich buche einen Flug, wenn ich in Urlaub fliege zum Beispiel, kann man auch als Transaktion bezeichnen.

[5:40] Also wenn zwei Geschäftspartner zusammen miteinander ein Geschäft machen zum Beispiel, das könnte man auch als Transaktion bezeichnen.

[5:45] Das ist hier aber nicht gemeint, sondern bei Datenbanken reden wir wirklich davon, mehrere zusammenhängende Statements, die ich gegen die Datenbank absenden will, werden als Einheit durchgeführt.

[5:56] Das ist eine Transaktion.

[5:58] Und in diesem ersten schlechten Beispiel, deswegen, weil die Begriffe so durcheinander schmeißbar sind, würde man das, was die Bank da macht, nämlich die Überweisung, auch als Transaktion bezeichnen.

[6:08] Aber das hat halt nichts mit dieser Datenbanktransaktion zu tun.

[6:11] Deswegen finde ich das Beispiel immer ein bisschen blöd, weil dann die Prüflinge schnell den Begriff so ein bisschen durcheinander schmeißen.

[6:15] Und auf einmal redet man die ganze Zeit nur noch von Überweisung anstatt über Datenbanktransaktion.

[6:19] Deswegen habe ich noch ein paar mehr Beispiele mitgebracht, damit es ein bisschen deutlicher wird.

[6:23] Die Banküberweisung ist so das Standardbeispiel.

[6:25] Ich habe es jetzt hier auseinandergedröselt, um das auseinanderzuhalten, die beiden Begriffe der Transaktion.

[6:30] Aber die nächsten drei, da wird das dann hoffentlich noch ein bisschen deutlicher.

[6:33] Schauen wir uns an, ich habe also wirklich eine ganz andere Domäne.

[6:36] Ich habe einen Blog, da habe ich einen Blogpost geschrieben und da möchte ich jetzt einen Tag an diesen Blogpost machen.

[6:41] Sowas wie, keine Ahnung, Datenbank oder in meinem Fall jetzt Katze.

[6:45] Ich habe natürlich ein lustiges Video gepostet oder so und da muss dringend der Tag dran Katze.

[6:50] Wie könnte das aussehen?

[6:51] Angenommen, es gibt diesen Tag bisher noch nicht.

[6:54] Also ich habe gerade meinen allerersten Blogpost geschrieben, wo irgendwas mit Katzen drin ist.

[6:58] Dann müsste ich folgendes machen.

[6:59] Ich müsste den Tag erstmal anlegen in der Datenbank und dann müsste ich den Blogpost mit dem Tag verknüpfen.

[7:04] Denken wir uns ein ganz normales relationales Datenmodell, dann wäre das wahrscheinlich eine M zu N Kardinalität,

[7:11] weil ein Tag an mehreren Blogposts hängen kann, ein Blogpost aber auch mehrere Tags haben kann.

[7:16] Also M zu N.

[7:17] Das heißt, ich habe eine Zuordnungstabelle.

[7:19] Ich nenne die mal der Einfachheit halber TagPost, wo einfach die beiden IDs drin sind.

[7:23] Und dann habe ich eine Stammdatentabelle, wo alle Tags drin stehen.

[7:26] Die nenne ich einfach mal Tag.

[7:28] Und wenn ich das jetzt umsetzen müsste, dann müsste ich das in eine Transaktion zusammenfassen.

[7:32] Einmal das Anlegen des Tags, den es noch nicht gab.

[7:35] Das wäre sowas wie ein Insert into Tag, wo dann irgendwie Katze eingefügt wird.

[7:39] Und ich müsste aber auch das Verknüpfen des Tags mit dem Blogpost natürlich gemeinsam damit machen.

[7:44] Das heißt sowas wie Insert into TagPost, wo dann die Blogpost-ID mit dem TagID verknüpft wird zum Beispiel.

[7:53] Das sollte auch als Einheit stattfinden, weil wenn eins davon nicht gemacht wird,

[7:57] dann habe ich entweder den Tag gar nicht angelegt.

[7:59] Das wäre blöd, weil dann hat der Blogpost einen Verweis auf einen Tag, den es nicht gibt.

[8:03] Das wäre schlecht.

[8:04] Oder ich lege halt nur den Tag an, aber ich verknüpfe ihn nicht mit dem Blogpost.

[8:07] Dann hat der Blogpost gar keinen Tag und ich habe einen Tag, der keinen Blogpost hat.

[8:10] Also auch uncool.

[8:12] Das heißt, beide Sachen müssten schon gemeinsam durchgeführt werden und sollten daher als Transaktion laufen.

[8:17] Nächstes Beispiel. Ich will eine Bestellung erfassen.

[8:20] Ein Kunde kauft bei uns was.

[8:22] Der Kunde hat eine ID.

[8:23] Der Artikel, den er kauft, hat auch eine ID.

[8:25] Die gibt es schon in der Datenbank.

[8:26] Aber es gibt die Bestellung noch nicht.

[8:27] Dann müsste ich zum Beispiel ein Insert into Bestellung machen

[8:30] und da dann irgendwie eine neue Bestell-ID und ein Datum und den Kunden eintragen und so weiter.

[8:35] Und ich muss aber auch mit dieser Bestellung direkt den Artikel verknüpfen, der da bestellt wird.

[8:39] Und das ist dann üblicherweise eine andere Tabelle, nämlich sowas wie Bestellposition.

[8:43] Und dann würde ich sowas machen wie Insert into Bestellposition mit der ID der Bestellung,

[8:48] die ich gerade angelegt habe im ersten Statement und damit dann zum Beispiel den Artikel verknüpfen.

[8:53] Das heißt, die beiden Statements sollten auch bitte zusammenhängend durchgeführt werden.

[8:58] Sonst habe ich, wenn ich nur die Bestellung anlege, halt eine leere Bestellung ohne Artikel.

[9:02] Das ist wenig sinnvoll.

[9:03] Und andersherum ist es noch schlimmer.

[9:05] Ich habe die Bestellung nicht angelegt, aber trage schon mal einen Artikel ein für die Bestellung, die es nicht gibt.

[9:09] Das ist ja auch Banane.

[9:11] Darf es nicht sein.

[9:12] Das heißt, diese Statements müssen gemeinsam durchgeführt werden oder gar nicht.

[9:16] Also als Transaktion.

[9:18] Und letztes Beispiel.

[9:19] Ich komme ja aus einer Krankenversicherung.

[9:21] Wie kann ich dann auch vergessen, irgendwas über die Versicherung zu machen?

[9:24] Das geht natürlich nicht.

[9:25] Deswegen, angenommen, wir haben einen Tarifsatz.

[9:27] Am 1.1. zum Beispiel wird die Versicherung teurer.

[9:30] Ist meistens so.

[9:31] Dann ist es meist so, dass ich eine Tabelle habe.

[9:33] Erst mal ganz simpel und vereinfacht.

[9:35] Datenmodelle in der Versicherung können sehr komplex werden.

[9:37] Aus eigener Erfahrung kann ich das sagen.

[9:38] Aber stellen wir uns das mal ganz einfach vor.

[9:40] Ich habe sowas wie eine Tabelle Tarif.

[9:42] Und da steht drin, gültig ab.

[9:44] Datum, gültig bis.

[9:45] Und dann der Beitrag, der gezahlt werden muss.

[9:47] Und jetzt habe ich einen offenen Tarif zum Beispiel.

[9:50] Da steht dann schon sowas drin wie, gültig ab.

[9:52] Weiß ich nicht.

[9:53] 2020.

[9:54] Und ich zahle 100 Euro.

[9:55] Und ab 2024 möchte ich jetzt, oder möchte die Versicherung, dass ich 120 Euro zahle.

[10:00] Was muss ich dann machen?

[10:01] Dann muss ich den bestehenden aktuellen Datensatz nehmen.

[10:04] Und da das Endedatum setzen.

[10:06] Und einen neuen Satz anlegen.

[10:08] Der dann mit dem neuen Datum startet.

[10:11] Das heißt, ich müsste einmal sowas machen wie Update Tarif.

[10:15] Und das gültig bis Datum setzen.

[10:17] Und dann müsste ich auch noch ein Insert Into Tarif machen.

[10:20] Mit dem neuen Datensatz, der bei diesem Endedatum beginnt.

[10:23] Sodass der alte Satz beendet wird und der neue Satz anfängt.

[10:27] Wieder zwei zusammenhängende Änderungen, die ich gemeinsam machen muss.

[10:31] Denn wenn ich nur den alten Satz zumache, ohne einen neuen anzulegen,

[10:34] muss der Kunde gar nichts mehr bezahlen.

[10:36] Das wäre schlecht.

[10:37] Und wenn ich nur den neuen anlege, ohne den alten zu beenden,

[10:40] habe ich auf einmal zwei offene Sätze.

[10:42] Und dann muss der Kunde zweimal zahlen.

[10:43] Das wäre auch schlecht.

[10:44] Also darf nicht passieren.

[10:45] Das muss beides zusammen durchgeführt werden oder gar nicht.

[10:48] Jetzt haben wir vier verschiedene Beispiele für sinnvolle Transaktionen.

[10:52] Aus ganz unterschiedlichen Domänen.

[10:54] Ich hoffe, das konntest du dir jetzt merken.

[10:56] Und musst nicht immer das gute alte Beispiel der Banküberweisung nehmen.

[10:59] Eben weil man das so leicht durcheinander bringen kann.

[11:01] Drei andere Beispiele habe ich dir noch geliefert.

[11:03] Ich hoffe, es ist ein bisschen klarer geworden.

[11:05] Eine Datenbanktransaktion bedeutet,

[11:07] ich habe mehrere gemeinsam durchgeführte Statements,

[11:10] die ich quasi als eine Einheit behandeln möchte.

[11:13] Und entweder werden die alle durchgeführt oder gar keiner.

[11:15] Aber es wird nicht in der Mitte abgebrochen und nur die Hälfte gemacht.

[11:18] Das darf nicht passieren.

[11:19] Und ich sage es nochmal ganz deutlich,

[11:21] das ist nicht eingeschränkt auf Insert, Update oder sonst was.

[11:24] Das können beliebige Statements sein,

[11:25] die zusammen hintereinander durchgeführt werden müssen.

[11:28] So, jetzt wissen wir, was eine Datenbanktransaktion ist.

[11:31] Jetzt sollen die aber auch noch gewisse Eigenschaften haben.

[11:35] Und die hat man zu einem schönen Akronym zusammengefasst.

[11:38] Und zwar sind das die ACID-Prinzipien.

[11:40] ACID, das englische Wort für Säure.

[11:42] ACID.

[11:44] Und dieses Akronym, diese vier Buchstaben,

[11:46] die stehen für die Anfangsbuchstaben der englischen Begriffe,

[11:49] die damit gemeint sind.

[11:50] ACID.

[11:51] Und zwar auf Englisch Atomicity, Consistency, Isolation und Durability.

[11:57] Auf Deutsch heißen die Atomarität, Konsistenz, Isolation und Dauerhaftigkeit.

[12:03] Man nimmt aber gerne die englischen Begriffe,

[12:05] die versteht jeder und kennt jeder.

[12:07] Die deutschen sind so ein bisschen meh.

[12:08] Deswegen gehe ich auch mal auf die englischen ein.

[12:10] Das ACID kommt ja auch von englischen Begriffen.

[12:12] Ist selber auch ein englisches Wort.

[12:14] Also das ergibt alles nur Sinn, wenn wir das auf Englisch machen.

[12:17] Deswegen bleiben wir mal dabei.

[12:18] Das heißt Atomicity, Consistency, Isolation, Durability.

[12:22] Was bedeutet das?

[12:23] Also diese Prinzipien, diese ACID-Prinzipien,

[12:26] das sind vier Eigenschaften,

[12:27] die Transaktionen in einer Datenbank aufweisen sollten.

[12:30] Wenn ich eine Datenbank entwickle, programmiere, bereitstelle,

[12:34] meinen Kunden verkaufe und sage, die kann Transaktionen,

[12:38] dann würde ich erwarten, dass die diese vier Prinzipien umsetzt.

[12:41] Wenn ich also eine Transaktion durchführe mit der Datenbank,

[12:44] dann erwarte ich, dass alle diese vier Kriterien, Prinzipien,

[12:47] wie ich es auch immer nennen will, dass die eingehalten werden.

[12:50] Und die gehen wir jetzt mal der Reihe nach durch.

[12:52] Nummer eins ist das, was am einfachsten zu verstehen ist,

[12:54] denn das habe ich die ganze Zeit schon so ganz nebenbei erzählt,

[12:57] und zwar Atomarität, Atomicity.

[12:59] Diese Transaktion, einige nennen das so wie eine Art Klammer,

[13:04] die klammert mehrere einzelne Datenbank-Operationen so zusammen,

[13:09] dass sie wie eine Einheit aussehen.

[13:11] Atomar, das kennen wir auch noch aus der Normalisierung zum Beispiel,

[13:16] in der ersten Normalform nur atomare Werte.

[13:18] Atomar heißt ja nicht weiter teilbar.

[13:21] Wie ein Atom in der realen Welt, das sich nicht teilen kann.

[13:24] Ja, ich weiß, es gibt Kernspaltungen, lalala,

[13:26] aber wir gehen mal davon aus,

[13:27] dass man normalerweise Atome nicht teilen kann.

[13:29] Deswegen Atomar.

[13:31] Und diese, sage ich mal, zwei Statements zum Beispiel,

[13:34] wie das letzte Beispiel eben mit dem Tarifsatz,

[13:36] ein Insert, ein Update,

[13:37] die werden entweder gemeinsam als eine Einheit komplett durchgeführt,

[13:41] oder eben gar nicht.

[13:43] Aber es geht nicht, dass nur Teile davon durchgeführt werden.

[13:46] Und genau das Teilen heißt ja,

[13:48] ich kann den Atomkern nicht weiter teilen,

[13:50] also die Transaktion ist Atomar.

[13:53] Und das muss die Datenbank mir zur Verfügung stellen.

[13:56] Wenn ich also sage, ich starte jetzt eine Transaktion

[13:58] und dann führe ich meine ganzen Statements durch

[14:00] und dann sage ich, jetzt beende ich die Transaktion,

[14:02] dann wird alles, was dazwischen ist,

[14:04] innerhalb dieser Transaktionsklammer

[14:07] wie eine Einheit nach außen hin durchgeführt.

[14:09] Wenn du mal so ein bisschen programmiert hast,

[14:11] und ich gehe da mal von aus als IT-ler oder IT-lerin,

[14:14] und du kennst Sprachen, die Blöcke verwenden,

[14:17] wie zum Beispiel Java mit diesen geschweiften Klammern.

[14:19] Die geschweiften Klammern, die definieren Blöcke.

[14:22] Und das ist im Prinzip genau das gleiche Prinzip.

[14:24] Denn der Block ist dazu da,

[14:26] die darin enthaltenen Statements nach außen hin

[14:29] wie ein einziges Statement aussehen zu lassen.

[14:32] Wenn ich zum Beispiel ein If-Statement habe,

[14:34] das hat ja einen If-Block und einen Else-Block.

[14:36] Dieser Block ist nur dafür da,

[14:38] damit ich beim If und beim Else

[14:39] nicht nur ein einziges Statement reinschreiben kann,

[14:41] sondern auch mehrere.

[14:42] Wenn im If-Fall halt fünf Sachen gemacht werden sollen,

[14:45] dann kann ich die halt einfach untereinander schreiben

[14:47] und mache so eine Klammer drum,

[14:48] und dann wirkt das wie ein Statement,

[14:50] was ich dem If übergebe.

[14:52] Dafür sind diese Klammern da,

[14:53] und genauso ist es bei der Transaktionsklammer.

[14:55] Alles, was zwischen Starte und Beende Transaktion steht,

[14:58] sieht für die Datenbank aus wie eine einzige Aktion,

[15:01] die entweder ganz oder gar nicht durchgeführt wird.

[15:04] Das ist die Idee dabei.

[15:06] So, die nächste Eigenschaft nach Atomicity ist die Consistency.

[15:11] Und Konsistenz auf Deutsch, Konsistenz der Daten,

[15:14] bedeutet, dass die Transaktion die Datenbank

[15:17] in einem konsistenten Zustand hinterlässt.

[15:20] Nehmen wir mal ein Beispiel.

[15:21] Angenommen, ich hätte bei dieser Überweisung,

[15:24] die ich jetzt die ganze Zeit hatte,

[15:25] Konto A abbuchen, Konto B wieder drauf buchen.

[15:27] Wenn ich mittendrin abbreche und nur einen Teil ausführe,

[15:30] dann ist die Datenbank nachher inkonsistent.

[15:32] Warum?

[15:33] Weil ich entweder Geld aus dem Nichts erschaffen habe,

[15:35] was auf einmal da ist, oder ich habe Geld verloren.

[15:38] Entweder hat einer zu viel auf dem Konto,

[15:40] aber es wurde nirgendwo abgebucht oder umgekehrt.

[15:42] Und das ist inkonsistent.

[15:44] Die Daten sind inkonsistent.

[15:46] Die Geldmenge, die insgesamt zur Verfügung steht,

[15:48] hat sich erhöht oder verringert.

[15:49] Und das kann nicht sein.

[15:50] Denn wenn ich nur von A nach B was umbuche,

[15:52] dann kann nicht auf einmal mehr Geld auf der Bank sein als vorher.

[15:55] Das darf nicht passieren.

[15:57] Das heißt, es ist dann inkonsistent.

[15:58] Und die Transaktionen müssen jetzt so funktionieren,

[16:01] dass, und das ist jetzt ganz wichtig,

[16:03] sofern die Datenbank vor der Transaktion

[16:05] in einem konsistenten Zustand war, sie es auch nachher ist.

[16:08] Es kann natürlich nicht sein,

[16:09] wenn ich jetzt komplett Kraut und Rüben in meiner Datenbank habe

[16:12] und alles ist völlig inkonsistent,

[16:13] dass ich eine Transaktion durchführe und danach ist alles heile.

[16:16] Das kann natürlich nicht funktionieren.

[16:17] Aber es ist so, wenn die Datenbank vorher konsistent war,

[16:20] dann muss die Transaktion sicherstellen,

[16:22] dass sie es nachher auch noch ist.

[16:23] Also eine Transaktion kann nicht irgendeinen Quatsch machen

[16:26] und am Ende sind die Daten inkonsistent.

[16:29] Das darf nicht sein.

[16:30] Das bedeutet dieser zweite Punkt, Consistency, Konsistenz.

[16:35] Der dritte Punkt von ACID, A, Atomicity, C, Consistency,

[16:40] Isolation kommt jetzt, Isolation.

[16:43] Die Transaktionen,

[16:44] es können ja durchaus mehrere auf einer Datenbank laufen,

[16:46] dürfen sich nicht gegenseitig beeinflussen.

[16:48] Die müssen isoliert voneinander ablaufen.

[16:51] So ein bisschen wie bei Unit-Tests.

[16:52] Wenn man Unit-Tests programmiert, will ich auch nicht,

[16:54] dass der eine Test den anderen beeinflusst.

[16:55] So, der erste Test ändert irgendwie einen Wert in der Variablen

[16:58] und der zweite Test verlässt sich drauf.

[17:00] Und wenn ich die in unterschiedlichen Reihenfolgen ausführe,

[17:02] bricht der Test auf einmal.

[17:03] Sowas darf nicht passieren.

[17:04] Die müssen isoliert voneinander sein.

[17:05] Und ganz wichtig ist das gerade auch bei Datenbanken,

[17:07] dass diese Transaktionen isoliert voneinander sind.

[17:09] Denn sonst könnten die sich gegenseitig beeinflussen.

[17:11] Warum ist das wichtig?

[17:12] Naja, Datenbanken, die haben wir uns ja nicht aus Spaß ausgedacht.

[17:16] Wir könnten ja auch einfach unsere Daten einfach in Textdateien schreiben.

[17:18] Warum muss ich mir eine teure Datenbank kaufen?

[17:20] Weil die natürlich ein paar Vorteile hat gegenüber Textdateien.

[17:22] Unter anderem, dass ich parallelen Zugriff darauf ermöglichen kann.

[17:26] Wenn ich ein großes SAP-System habe

[17:28] und nur eine Person gleichzeitig damit arbeiten könnte,

[17:30] dann würde, glaube ich, niemand SAP kaufen.

[17:33] Ich brauche eine Datenbank, weil ich mit mehreren Personen,

[17:36] Systemen, Menschen, wie auch immer, gleichzeitig damit arbeiten möchte.

[17:40] Das heißt, es ist sogar sehr wahrscheinlich,

[17:42] dass im Alltagsbetrieb meiner Datenbank

[17:45] mehrere gleichzeitige Transaktionen gestartet werden.

[17:48] Und die dürfen sich eben nicht gegenseitig beeinflussen.

[17:51] Die müssen isoliert voneinander ablaufen.

[17:54] Und im Prinzip kann man sich das so vorstellen,

[17:56] wir kommen da gleich noch einmal im Detail zu, zu dieser Isolation,

[17:59] aber ganz einfach kann man sich das so vorstellen,

[18:01] die Transaktion, wenn ich zwei habe, Transaktion 1 und 2,

[18:04] dann muss die Datenbank dafür sorgen, jetzt mal ganz einfach gesagt,

[18:06] dass erst Transaktion 1 komplett durchläuft

[18:09] und danach die zweite Transaktion startet.

[18:11] Damit zum Beispiel Transaktion 2

[18:14] auf dem Ergebnis der Transaktion 1 aufsetzen kann

[18:17] und nicht mit irgendwelchen Zwischenwerten arbeitet,

[18:19] die noch gar nicht gespeichert sind oder sonstige Dinge.

[18:21] Wie gesagt, ich gehe gleich noch mal ein bisschen mehr auf die Isolation ein,

[18:24] aber so kann man sich es erst mal grob vorstellen.

[18:26] Das wäre die einfachste Möglichkeit, die erste Transaktion startet

[18:30] und alle anderen, die jetzt kommen, müssen einfach warten,

[18:32] bis die erste fertig ist.

[18:34] Das wäre die einfachste Möglichkeit, das zu lösen.

[18:36] Leider auch die nicht so optimale für den Alltagsbetrieb,

[18:40] weil wenn ich eine Datenbank unter hoher Last habe

[18:42] und die ganzen Transaktionen müssen aufeinander warten,

[18:45] dann wird das dadurch natürlich nicht schneller

[18:47] und die Benutzer werden sich wahrscheinlich schnell beschweren,

[18:49] warum die Datenbank so langsam ist.

[18:50] Von daher, wie gesagt, wir gehen gleich noch mal im Detail darauf ein,

[18:52] aber nur von der Idee her erst mal,

[18:54] zwei Transaktionen dürfen nicht sich gegenseitig beeinflussen können.

[18:58] Letzter Punkt, das D, Durability,

[19:01] das heißt auf Deutsch halt Dauerhaftigkeit

[19:03] oder auch Persistenz wird es meistens oder manchmal genannt.

[19:06] Das heißt, die Daten müssen dauerhaft, persistent gespeichert werden.

[19:09] Und nicht nur im Speicher, also im Arbeitsspeicher flüchtig gehalten werden.

[19:13] Wenn die Transaktion abgeschlossen ist,

[19:15] dann müssen die Daten persistent, also dauerhaft gespeichert in der Datenbank liegen.

[19:20] Man könnte auch sagen, die müssen dann auf der Festplatte liegen.

[19:23] Wenn du dich so ein bisschen mit Datenbanken auseinandersetzt,

[19:25] wenn ich auf die Datenbank zugreife,

[19:29] dann wird die ganz viele Daten nicht direkt immer von der Festplatte lesen,

[19:32] sondern wenn sie die einmal gelesen hat, im Arbeitsspeicher, Zwischenspeicher.

[19:36] Weil, vielleicht hast du es mal gesehen,

[19:38] was so die Geschwindigkeiten angeht der verschiedenen Speicher im PC.

[19:41] Der Arbeitsspeicher im Verhältnis zum Cache in der CPU ist schon sehr langsam,

[19:46] aber die Festplatte im Verhältnis zum Arbeitsspeicher,

[19:49] das sind Faktor, ich weiß nicht, 10.000, 100.000,

[19:52] das heißt, es ist wirklich extrem langsam.

[19:55] Eine Datenbank, die einigermaßen performant arbeitet,

[19:57] wird also nicht jeden Fitzel von der Festplatte lesen,

[19:59] sondern wird das alles in den Speicher ziehen,

[20:01] also in den Arbeitsspeicher, in den RAM ziehen.

[20:03] Und von da aus die Anfragen beantworten.

[20:06] Und wenn jetzt aber eine Transaktion nur im RAM läuft, ja, und jetzt bricht zum Beispiel nach der Transaktion mein PC zusammen, weil Stromausfall,

[20:14] oder, ne, jemand hat den Stecker gezogen, oder einfach die Datenbank stürzt ab, ne, ist ja auch nur ein Programm, das kann ja einen Fehler haben, das kann man abbrechen,

[20:20] dann wären die Daten eben nicht persistent, sondern nur flüchtig gespeichert, nämlich im Arbeitsspeicher.

[20:25] Und der Arbeitsspeicher hat den kleinen Nachteil, wenn der Strom weg ist, dann sind die Daten weg, ne,

[20:30] deswegen haben wir ja Festplatten, denn die sind auch noch da, wenn ich den Strom wieder anstelle.

[20:33] Das heißt, nach einer Transaktion muss die Datenbank die Daten persistent, also dauerhaft,

[20:39] und damit meint man zum Beispiel einen Systemausfall überstehend, abgelegt haben.

[20:45] Oder anders gesagt, auf der Festplatte, ja.

[20:47] Wie macht man das, ganz kurz vorweggenommen, weil ich kann jetzt nicht auf jedes der ACID-Dinger nochmal eingehen,

[20:52] bis auf die Isolation, die kommt ja gleich nochmal, aber ganz kurz, wie man das macht,

[20:55] Transaktionen oder Datenbanken, die Transaktionen anbieten, verwenden meistens sogenannte Transaktionslogs,

[21:01] das heißt, die Daten, die während der Transaktion verändert werden, werden in Log-Dateien,

[21:05] also wirklich physikalische Dateien auf der Festplatte geschrieben, wo dann drinsteht,

[21:09] ich habe das, ich habe das, ich habe das gemacht.

[21:11] Beispiel bei der Banküberweisung, ich habe Konto A erhöht und Konto B verringert.

[21:15] So, das schreiben die in das Transaktionslog.

[21:17] Und wenn jetzt nach dieser Transaktion die Datenbank abrauchen sollte, und ich fahre die wieder hoch,

[21:22] dann erkennt die, oh, ich habe hier im Log noch Einträge, die ich noch nicht in der wirklichen Datenbank gespeichert habe,

[21:26] und dann geht die dieses Log einfach von oben nach unten durch und speichert das dann alles in der Datenbank.

[21:30] Das heißt, das ist so eine Art Zwischenspeicher zwischen dem Rahmen und der wirklichen Datenhaltung auf der Festplatte,

[21:36] weil manchmal dauert das ein bisschen, bis das da landen kann.

[21:39] Die Daten müssen vielleicht umorganisiert werden, der Zugriff ist langsam,

[21:42] und deswegen geht man diesen Zwischenweg über Transaktionslogs, wo das dann reingeschrieben wird.

[21:46] Andere Datenbanken lösen das vielleicht anders, die meisten, die ich kenne, verwenden solche Transaktionslogs.

[21:52] So, damit ist die Dauerhaftigkeit dann hoffentlich gewährleistet.

[21:55] Also, wir haben die Asset-Prinzipien, nachdem eine Transaktion durchgeführt wurde,

[22:00] müssen oder während die durchgeführt wurde, oder insgesamt, müssen diese Asset-Prinzipien gelten.

[22:04] Ich fasse nochmal zusammen.

[22:05] Atoma, alle Statements dieser Transaktion werden entweder ganz oder gar nicht durchgeführt.

[22:12] Konsistenz, wenn die Datenbank vor der Transaktion konsistent war, ist sie es auch danach, muss sie es auch danach sein.

[22:20] Isolation, wenn mehrere Transaktionen parallel gleichzeitig ablaufen, dürfen die sich nicht gegenseitig beeinflussen.

[22:26] Und Dauerhaftigkeit, die Daten müssen nach der Transaktion persistent abgelegt sein,

[22:32] und es reicht nicht, wenn die nur im Speicher, also im Arbeitsspeicher, im RAM, abgelegt sind.

[22:36] Das sind die Asset-Prinzipien, und die kann man hervorragend auswendig lernen,

[22:40] für schriftliche Prüfungen, für mündliche Prüfungen, für alles Mögliche.

[22:42] Also gerne nochmal anhören, wenn du das nochmal vertiefen musst oder möchtest.

[22:48] So, jetzt habe ich schon angekündigt, einen Buchstaben wollen wir ein bisschen vertiefen, und zwar das Isolation.

[22:52] Weil das ist das, was man sich vielleicht am schlechtesten vorstellen kann, weiß ich nicht,

[22:56] aber wo es verschiedene Möglichkeiten gibt auch, wie man das implementieren könnte.

[22:59] Die Isolation ist halt ein ganz wichtiger Punkt bei Datenbanken, weil das macht halt den großen Vorteil von Datenbanken aus,

[23:06] ich kann mit mehreren Menschen parallel daran arbeiten.

[23:09] Und deswegen ist die Isolation so wichtig, weil das führt automatisch dazu,

[23:12] wenn mehrere Leute gleichzeitig daran arbeiten, dass es solche Konflikte geben wird.

[23:16] Dass mehrere Transaktionen gleichzeitig laufen, und damit muss die Datenbank umgehen können.

[23:20] Und deswegen gibt es da auch verschiedene Möglichkeiten, wie man das lösen kann.

[23:24] Und ich fange mal mit dem an, was ich ganz kurz eben schon angesprochen habe.

[23:28] Das ist so die, ich sage mal, gefühlt die einfachste Lösung, ist aber auch gleichzeitig leider so die schlechteste für den Alltag.

[23:35] Und ich fange mal so an, es gibt vier Möglichkeiten.

[23:39] Das Ganze heißt Read Uncommitted, Read Committed, Repeatable Read und Serializable.

[23:45] Das sind so die vier, sage ich mal, Stufen, die eine Datenbank anbieten kann, um die Isolation sicherzustellen.

[23:51] Das sind die sogenannten Transaktions-Isolations-Ebenen.

[23:56] So heißen die ja. Transaktion, Isolation, Ebene.

[23:59] Welche Ebene die Datenbank anbietet, das kann halt unterschiedlich sein.

[24:02] Es gibt halt eben diese vier verschiedenen Ebenen.

[24:05] Es muss nicht jede Datenbank jede oder eine bestimmte davon anbieten,

[24:08] sondern man kann das teilweise auch auswählen, welche man denn haben möchte.

[24:12] Je nachdem, ob die Datenbank oft gleichzeitig benutzt wird oder nicht.

[24:16] Wenn ich zum Beispiel eine Datenbank für mich selber, für mich alleine als einziger Anwender meiner eigenen Anwendung gebaut habe,

[24:21] gut, dann brauche ich vielleicht keine hohe Transaktions-Isolations-Ebene, weil ich bin der Einzige, der das nutzt.

[24:26] Habe ich, wie vorhin mein Beispiel SAP, wo tausend Leute gleichzeitig daran arbeiten,

[24:30] muss ich halt da vielleicht mal ein bisschen anders rangehen und die Sache durchsagen.

[24:34] Gut, grundsätzlich, wie funktioniert das?

[24:36] Bei mehreren Transaktionen kann man sich das ganz simpel so vorstellen.

[24:39] Es werden einfach Sperren gesetzt in der Datenbank und die Datenbank kann sagen,

[24:43] zum Beispiel, die Datensätze in dieser Tabelle dürfen jetzt nur gelesen werden

[24:46] oder die dürfen nur geschrieben werden oder gar nichts von beiden.

[24:49] Die werden komplett gesperrt für irgendwen, der darauf will.

[24:51] Und solche Sperren, eine Lese-Sperre oder eine Schreib-Sperre, die kann halt gesetzt werden.

[24:56] Für eine ganze Tabelle, für einen einzelnen Datensatz, für mehrere Tabellen, für alles Mögliche könnte die Datenbank sagen,

[25:01] so, ich stelle jetzt hier eine Sperre ein, ein LOCK, L-O-C-K, ich locke diese Daten.

[25:07] Und wenn jetzt jemand Zweites kommt und damit was machen will, dann kann er das nicht,

[25:11] weil diese Sperre halt gesetzt ist.

[25:12] Das ist so ein ganz effektives Verfahren, um einfach zu sagen, jemand möchte die Daten hier ändern,

[25:17] dann sperre ich die jetzt, solange bis der fertig ist und in der Zeit kann halt kein anderer dran.

[25:22] Und das wäre schon mal ein ganz simples Beispiel, wenn ich zwei verschiedene Tabellen habe,

[25:26] weiß ich nicht, einmal unsere Kunden und einmal unsere Artikel und zwei Mitarbeiter arbeiten parallel.

[25:31] Der eine pflegt die Kunden, der andere pflegt die Artikel.

[25:33] Warum soll ich dann, wenn ich den Kunden ändere, verbieten, dass jemand Artikel gleichzeitig ändert?

[25:38] Die können sich ja nicht gegenseitig beeinflussen.

[25:40] Ich kann einen Artikel hinzufügen und gleichzeitig einen Kunden hinzufügen.

[25:43] Das ist kein Problem.

[25:44] Wenn ich aber zwei Mitarbeiter habe, die ein und denselben Artikel gleichzeitig ändern wollen,

[25:49] dann wird es natürlich schwierig.

[25:51] Das funktioniert nicht.

[25:52] Sollte also einleuchten, dass mit diesen Sperren relativ feingliedrig gearbeitet werden kann, je nachdem, was ich brauche.

[25:58] Wenn ich gerade Kunden anlegen möchte, muss ich nicht die andere Tabelle Artikel sperren.

[26:03] Wenn ich aber gerade einen Kundensatz ändere, sollte vielleicht dieser einzelne Kundensatz für alle anderen Änderungen gesperrt sein.

[26:11] Und so kann man das individuell und sehr feingliedrig festlegen, was die Datenbank da macht.

[26:15] Grundsätzlich kann ich sagen, etwas kann gelesen werden oder nicht oder etwas kann auch geschrieben werden oder nicht.

[26:21] Das kann man über solche Lese- und Schreibsperren setzen.

[26:24] Wenn wir jetzt ganz hinten anfangen, bei diesem Serializable,

[26:28] das würde so aussehen, dass die Datenbank einfach komplett alles sperrt, während eine Transaktion läuft.

[26:34] Erst wenn die durch ist, kann dann der zweite weitermachen.

[26:36] Ganz simpel gesagt.

[26:38] Das führt dann dazu, dass die Transaktionen nacheinander, also seriell, durchgeführt werden.

[26:44] Du kennst den Unterschied vielleicht zwischen seriell und parallel.

[26:47] Seriell bedeutet hintereinander, parallel bedeutet gleichzeitig.

[26:51] Das heißt, drei Sachen will ich machen.

[26:53] Seriell 1, 2, 3.

[26:55] Parallel mache ich 1, 2, 3 gleichzeitig.

[26:58] So, das ist der Unterschied.

[26:59] Euren Akzent kennst du vielleicht von USB-Port.

[27:02] USB, Universal Serial Bus, weil der Bus seriell arbeitet und nicht parallel.

[27:07] Parallelanschluss zum Beispiel, wenn du schon so alt bist.

[27:10] Damals, als ich noch jung war, hat man Drucker noch über die parallele Schnittstelle angesprochen.

[27:16] Das war so ein ganz dicker, breiter Stecker, der dann irgendwie 40 Pole oder so hatte.

[27:21] Ich weiß nicht, ob es 40 waren, ehrlich gesagt, aber es waren mehr.

[27:24] Er konnte halt 40 Informationen gleichzeitig, also parallel, versenden.

[27:28] Kleiner Spoiler, heute ist fast alles seriell, weil die Technologie so weit fortgeschritten ist,

[27:33] dass die Geschwindigkeit seriell viel, viel höher ist, weil parallele Verarbeitung hat so leichte Problemchen.

[27:38] Zum Beispiel, wenn ich parallel was mache, muss ich die ganzen Daten streng auch irgendwie wieder zusammenkriegen.

[27:44] Parallele Programmierung ist eine super schwierige Herausforderung,

[27:47] weil ich warten muss, bis zum Beispiel die einzelnen Teilprobleme gelöst sind.

[27:50] Ich muss sie wieder zusammenbringen. Was ist, wenn einer davon abbricht?

[27:53] Also ganz, ganz viele Probleme macht diese Parallelität.

[27:56] Deswegen ist es viel einfacher, seriell zu arbeiten.

[27:58] Und für die Transaktionen ist es das auch.

[28:01] Anstatt zwei Transaktionen parallel laufen zu lassen mit den ganzen Problemen, die auftreten können,

[28:04] sage ich einfach, mach es doch nacheinander.

[28:07] Warte so lange, bis der ESC fertig ist und schon habe ich keine Probleme mehr.

[28:10] Und das wäre auch so, wenn ich in Richtung Datenkonsistenz und so weiter gucke,

[28:14] ist die serielle Lösung sicherlich das einfachste.

[28:16] Ich sage, meine Datenbank soll serializable arbeiten.

[28:19] Das bedeutet, die erste Transaktion startet und bis die fertig ist, kann halt kein anderer Transaktion starten. Ende.

[28:25] Das ist super einfach zu implementieren.

[28:27] Das Problem dabei ist, wie gesagt, habe ich mehrere parallele Bearbeitungen,

[28:31] dann müssen alle warten, bis die erste Transaktion fertig ist.

[28:35] Und wenn jetzt tausend Leute gleichzeitig in SAP arbeiten und einer speichert was,

[28:38] dann müssen 999 Leute warten, bis der fertig ist mit Speichern.

[28:42] Und das ist schlecht.

[28:44] Das heißt, ein richtiger Parallelbetrieb wäre dabei nicht so wirklich möglich,

[28:48] weil relativ schnell wahrscheinlich sehr viele Transaktionen auf andere Transaktionen warten müssen

[28:54] und dadurch ich einfach nicht mehr vernünftig arbeiten kann.

[28:56] Das wäre blöd.

[28:58] Also serializable wäre eine einfache Möglichkeit, ist aber extrem langsam,

[29:02] deswegen gibt es vielleicht noch andere Möglichkeiten.

[29:04] Und jetzt kann man halt diese Transaktionsisolationsebene ein bisschen rückwärts zurückgehen.

[29:08] Serializable ist so die höchste Ausprägung.

[29:10] Es wird alles einfach nacheinander gemacht und ich habe keine Probleme.

[29:14] Aber wenn ich jetzt eine Stufe zurückgehe, die heißt repeatable read,

[29:18] da werden während der Transaktion Lese- und Schreibsperren auf alle beteiligten Objekte gesetzt.

[29:24] Das kann man sich jetzt so vorstellen.

[29:26] Ich habe jetzt so eine Transaktion, meine Bestellung, die ich anlegen will.

[29:31] Da muss ich den Kunden aktualisieren und eine Bestellung und Artikel.

[29:34] Und dann würden für diese Transaktion die beteiligten Tabellen gesperrt,

[29:39] sodass kein anderer in der Zeit lesen oder schreiben kann.

[29:42] Und wenn die Transaktion fertig ist, wird sie wieder freigegeben.

[29:45] Das bedeutet aber, dass meine 795 anderen Tabellen in der Datenbank,

[29:48] die nichts mit Bestellung machen, während der Zeit ganz normal benutzt werden können.

[29:52] Aber wenn jemand anderes jetzt einen Kunden anlegen will in der Zeit, wo meine Transaktion läuft, geht das halt nicht.

[29:58] Das heißt, ein gewisser Teil meiner Daten ist gesperrt, aber halt nicht die komplette Datenbank.

[30:02] Und alle müssen auf mich warten.

[30:04] Das ist also schon ein bisschen eingeschränkt.

[30:06] Dadurch wird die Datenbank insgesamt etwas performanter, weil mehrere Sachen parallel gemacht werden können.

[30:12] Aber die Transaktion ist trotzdem relativ sicher, weil halt die Sachen, die ich ändern möchte, gesperrt sind in der Zeit.

[30:19] Gut, dann haben wir noch eine Stufe schlechter werdenden Anführungszeichen.

[30:24] Dann haben wir das read committed.

[30:26] Das bedeutet, dass für die gesamte Transaktion Schreibsperren auf alle beteiligten Objekte gesetzt werden.

[30:32] Vergleich mit repeatable read war, da werden sogar auch Lesesperren gesetzt.

[30:37] Also repeatable read macht Lese- und Schreibsperren auf alle beteiligten Objekte.

[30:40] Read committed macht nur Schreibsperren.

[30:43] Das heißt, wenn in der Zeit, wo die Transaktion läuft, jemand anderes die Sachen lesen will, kann er das machen.

[30:47] Beispiel, was könnte da passieren?

[30:49] Ich ändere gerade einen Kunden, ich möchte den speichern, aber jemand anderes liest genau in dem Zeitpunkt den Kunden.

[30:55] Welche Daten kriegt er jetzt angezeigt? Die, die ich schon aktualisiert habe in der Transaktion oder die vorher?

[31:00] Das ist schwierig.

[31:02] Das heißt, er könnte eventuell die falschen Daten lesen, aber er könnte sie nicht gleichzeitig zu mir ändern.

[31:08] Das wäre ja schon mal gut.

[31:10] Aber es ist ein bisschen schlechter als das repeatable read, weil es können halt andere Fehler auftreten.

[31:14] Aber dadurch kann trotzdem die Person halt mehr machen als beim repeatable read.

[31:22] Wenn wir uns vorstellen, beim repeatable read wird alles für Lesen und Schreiben gesperrt.

[31:26] Ich ändere einen Kunden und niemand anderes kann irgendeinen anderen Kunden lesen in der Zeit.

[31:31] Das ist schon relativ einschränkend, während ich bei read committed halt eben nur Schreibsperren setze.

[31:37] Das heißt, es kann munter gelesen werden in der Datenbank, während ich was ändere.

[31:41] Das ist doch okay.

[31:42] Denn wenn man sich mal überlegt, ganz allgemein bei Datenbanken, es wird viel, viel, viel, viel, viel, viel, viel häufiger da drin gelesen als geschrieben.

[31:50] Das heißt, wenn ich nur für die Schreibzugriffe sperre, habe ich den weitaus größten Anteil an Operationen,

[31:55] nämlich die lesenden Operationen, dadurch nicht beeinträchtigt.

[31:58] Und das ist natürlich schön.

[32:00] Trotzdem können noch ein paar Fehler auftreten, aber die gucken wir uns gleich an.

[32:03] Und dann gibt es noch die letzte Stufe, die schlechteste Stufe, und die heißt read uncommitted.

[32:08] Und dabei werden einfach gar keine Sperren verwendet.

[32:10] Ich vergleiche das immer ganz gerne mit der referenziellen Integrität.

[32:14] Kennst du vielleicht schon aus Datenbanken?

[32:17] Wenn die Fremdschlüssel alle auf gültige Primärschlüssel in anderen Tabellen zeigen, dann ist die referenzielle Integrität gewahrt.

[32:25] Und da gibt es, Überraschung, auch wieder vier Möglichkeiten, wie die Datenbank die wahren kann.

[32:30] Und die erste Möglichkeit ist no action.

[32:33] Und das heißt so ziemlich, die referenzielle Integrität interessiert mich nicht.

[32:37] Ich mache einfach nichts.

[32:38] Oder anders gesagt, die referenzielle Integrität wird einfach gar nicht gewahrt.

[32:41] Und das heißt da no action.

[32:43] Und dieses read uncommitted heißt für mich übersetzt bei Transaktionen interessiert mich nicht.

[32:47] Transaktionen werden nicht isoliert.

[32:49] Die laufen einfach, wie sie lustig sind quasi.

[32:51] Das heißt, es gibt da im Prinzip gar keinen Schutz.

[32:54] Wie gesagt, vergleichbar mit no action bei referenzieller Integrität.

[32:58] Trotzdem kann ich das natürlich so machen.

[33:00] Ist vielleicht blöd, das zu tun, aber ich könnte es ja machen, wenn mich das nicht so interessiert, dass meine Daten konsistent sind.

[33:06] Also das sind die vier Transaktions-Isolationsebenen.

[33:09] Read uncommitted. Es wird quasi gar nichts gesperrt.

[33:12] Dann haben wir read committed. Es wird nur eine Schreibsperre benutzt.

[33:16] Repeatable read. Es wird Lese- und Schreibsperre genutzt.

[33:19] Und serializable. Das wäre so, als würden die Transaktionen wirklich komplett isoliert nacheinander ablaufen.

[33:25] Und es wird quasi gar nichts anderes, während die Transaktion läuft, erlaubt.

[33:29] Das wäre so das Härteste, um die Konsistenz zu wahren, aber auch gleichzeitig das Schlimmste für den Parallelbetrieb.

[33:35] Und so kann man sich diese vier Ebenen grob vorstellen.

[33:39] So, jetzt habe ich bei der Erklärung die ganze Zeit schon von so Fehlern gesprochen, die da auftreten können.

[33:43] Und die gucken wir uns jetzt auch nochmal an.

[33:45] Denn es gibt tatsächlich so vier hübliche Fehler, die passieren können, wenn Transaktionen nicht isoliert voneinander ablaufen können.

[33:52] Und die können wir jetzt gleich auch diesen Isolationsebenen gleich mal zuordnen.

[33:56] Ich nenne die erstmal. Das sind dirty reads, lost updates, non-repeatable reads und phantom reads.

[34:03] Das sind wieder mal so vier englische schöne Begriffe.

[34:06] Und die beschreiben, was passieren kann, wenn die Transaktionen sich quasi gegenseitig beeinflussen und nicht isoliert sind.

[34:12] Erstens gucken wir uns mal an, das ist das dirty read.

[34:16] Da habe ich erstmal ein Beispiel, um einzusteigen.

[34:18] Wenn wir einen Ticketverkauf machen für ein beliebtes Konzert oder kann auch ein Flug sein oder so.

[34:24] Aber gehen wir mal von einem Ticket aus für ein Konzert.

[34:27] Wenn es da zwei Transaktionen für eine Konzertticketbuchung gibt und die zweite Transaktion geht schon vom verendeten Zustand der ersten Transaktion aus, obwohl die noch gar nicht fertig ist.

[34:37] Dann kann ein sogenanntes dirty read auftreten.

[34:40] Das heißt, veränderte Daten von einer anderen Transaktion, die noch nicht fertig ist, die nennt man dann dirty.

[34:46] Die sind verändert, die sind in einem dreckigen Zustand, die sind noch nicht festgeschrieben.

[34:50] Die sind quasi temporär, solange die erste Transaktion noch läuft, noch verändert.

[34:55] Und deswegen nennt man die dirty.

[34:57] Vorher waren sie sauber, wenn die Transaktion durch ist, sind sie auch wieder sauber.

[35:01] Aber während die in der Änderung sind, nennt man die dirty.

[35:03] Kennst du vielleicht aus der UI-Programmierung, wenn du schon mal was programmiert hast.

[35:06] Da kann man auch prüfen, ob Eingabefelder dirty sind.

[35:09] Angenommen, ich mache eine Anwendung, um Kunden zu verwalten.

[35:13] Wenn ich die Kundendaten bearbeiten möchte, dann mache ich die Maske auf mit meinen 27 Feldern.

[35:18] Die Daten werden aus der Datenbank in den Feldern angezeigt.

[35:21] Aber wie finde ich denn jetzt raus, welche Felder überhaupt vom Benutzer verändert wurden?

[35:25] Vielleicht will er ja gerade nur den Vornamen ändern und nicht die Postleitzahl.

[35:28] Wenn ich jetzt beim Abspeichern, wenn ich auf den Speichernknopf drücke, alle 27 Attribute speichere,

[35:33] dann speichere ich ja vielleicht was, was ich gar nicht speichern muss.

[35:36] Vielleicht sollte ich nur die Sachen speichern, die auch geändert wurden.

[35:39] Und da gibt es dann auch den Begriff von dirty fields.

[35:42] Das heißt, Sachen, die verändert wurden, heißen dann auch dirty.

[35:45] Und dann speichere ich nur die dreckigen Sachen und nicht die, die schon längst gespeichert sind.

[35:49] Und das ist das gleiche Prinzip hier.

[35:51] Daten stehen in der Datenbank. Eine Transaktion ändert die gerade.

[35:55] Und währenddessen läuft eine zweite Transaktion los, sieht aber schon diesen veränderten Zustand und nicht den, wie er vorher war.

[36:03] Und das ist dann ein sogenannter dirty read.

[36:05] Und dabei kann es Probleme geben.

[36:07] Angenommen, wir bleiben bei der Ticketbuchung.

[36:10] Und angenommen, irgendwer gibt gerade Tickets zurück, meinetwegen, weil er storniert seine Buchung oder sowas.

[36:17] Dann wird der Ticketbestand erhöht.

[36:20] Und eine zweite Transaktion, die losläuft, liest schon diesen erhöhten Stand und kauft vielleicht Tickets, die sie eigentlich noch gar nicht kaufen kann.

[36:26] Weil die Tickets wurden ja noch gar nicht zurückgegeben.

[36:28] Die Transaktion ist ja noch gar nicht beendet.

[36:30] Nur so als Beispiel, was man da konstruieren könnte.

[36:32] Also, ich lese Daten, die noch gar nicht wirklich persistiert sind.

[36:35] Das ist eine schlechte Idee.

[36:37] Der zweite Punkt ist eigentlich so der, den man sich am einfachsten erklären kann und der auch am schlimmsten ist.

[36:41] Und zwar die sogenannten lost updates.

[36:44] Angenommen, zwei Transaktionen bearbeiten gleichzeitig denselben Datensatz.

[36:48] Dann gewinnt die, die als zweites speichert.

[36:52] Beispiel, wieder Ticketverkauf.

[36:54] Oder bleiben wir bei der Banküberweisung.

[36:56] Wir haben ein Konto und ich habe zwei Überweisungen.

[37:00] Von meinem Konto sollen zwei Überweisungen abgebucht werden.

[37:02] Wenn ich mir das so vorstelle wie Update und zieh mal 100 Euro ab von meinem Konto.

[37:07] Und das zweite macht auch ein Update, zieh nochmal 50 Euro ab.

[37:10] Einmal 100, einmal 50.

[37:12] Dann starten die beiden Transaktionen parallel.

[37:14] Angenommen, mein Kontostand ist 1.000.

[37:16] Die erste Transaktion liest, oh, 1.000 Euro drauf, super.

[37:19] Zieht 100 Euro ab und speichert 900.

[37:21] Die zweite Transaktion liest auch 1.000, zieht 50 ab und speichert 950.

[37:26] So, das heißt, die erste Transaktion speichert 900.

[37:29] Die zweite speichert 950 und überschreibt damit die 900, die vorher hätte gespeichert werden müssen.

[37:36] Und was ist das Endergebnis?

[37:37] Ich habe 150 Euro überwiesen, aber mir wurden nur 50 Euro abgezogen.

[37:41] Das wäre cool, oder?

[37:42] Wenn das so funktionieren würde, sollte aber vielleicht besser nicht passieren.

[37:46] Das heißt, es wäre schon sinnvoll, wenn die erste Abbuchung erfolgreich durchgelaufen ist

[37:51] und mein Kontostand dann nur noch 900 Euro beträgt,

[37:53] dass dann erst die zweite Transaktion losläuft und davon die 50 Euro abzieht

[37:57] und nicht vom gemeinsamen vorherigen Stand von 1.000.

[38:00] Das darf nicht passieren.

[38:01] Und das ist ein Lost Update, weil das erste Update, wo die 100 Euro abgebucht wurden,

[38:05] das ist jetzt verloren, weil es durch die 50 Euro der zweiten Überweisung überschrieben wurde.

[38:10] Und das darf nicht passieren, weil jetzt haben wir wieder Geld aus dem Nichts erschaffen.

[38:14] Mein Kontostand ist viel zu hoch.

[38:15] Ich habe mehr Geld abgebucht, als mir wirklich abgezogen wurden.

[38:19] Und das darf natürlich nicht passieren.

[38:20] So, dann haben wir noch zwei weitere Punkte.

[38:22] Das Non-Repeatable Read.

[38:24] Das bedeutet, dass innerhalb einer Transaktion Lesevorgänge unterschiedliche Ergebnisse liefern.

[38:29] Warum brauche ich in einer Transaktion Lesevorgänge?

[38:32] Für das Speichern der Daten ist relativ offensichtlich, dass es in der Transaktion ablaufen soll.

[38:36] Aber manchmal muss ich auch innerhalb der Transaktion was nachlesen.

[38:39] Beispiel, ich muss irgendwie eine ID ermitteln, die ich in einem anderen Datensatz speichern muss.

[38:44] Da muss ich erst mal ein Select machen, um dann vielleicht irgendwo ein Insert oder Update zu machen.

[38:48] Oder Beispiel, ich will das Durchschnittsgehalt meiner Mitarbeiter ermitteln und das dann in einer anderen Tabelle speichern.

[38:55] Da muss ich erst mal ein Select some irgendwas from Employees machen, um das Ergebnis dann irgendwo abzuspeichern.

[39:01] Also es geht nicht immer nur ums Schreiben, sondern auch ums Lesen.

[39:04] Und ein Non-Repeatable Read heißt jetzt, wörtlich übersetzt, ein nicht wiederholbares Lesen.

[39:10] Das heißt, wenn ich zweimal lese innerhalb einer Transaktion, kriege ich unterschiedliche Ergebnisse.

[39:15] Und das ist doof.

[39:16] Das kann auch passieren, wenn sich Transaktionen eben nicht voneinander isoliert ausführen lassen.

[39:20] Beispiel, bei einer Flugbuchung prüfe ich, ob noch ausreichend Plätze frei sind.

[39:24] Da gucke ich erst mal, die Person möchte drei Sitzplätze buchen.

[39:27] Habe ich überhaupt noch drei?

[39:28] Und dann mache ich sowas wie, keine Ahnung, Select und Count und ich weiß nicht was, ob noch genug Plätze frei sind.

[39:33] Und dann buche ich das und stelle danach aber fest, wenn ich das nochmal kontrolliere,

[39:37] oh scheiße, die Zahl hat sich in der Zwischenzeit geändert.

[39:39] Weil eine andere Transaktion hat zum Beispiel gleichzeitig einen Platz gebucht oder wahlweise auch einen Platz storniert, ist ganz egal.

[39:45] Aber das zweite Read, das zweite Select, liefert mir jetzt ein anderes Ergebnis.

[39:49] Vorher waren, weiß ich nicht, 27 Plätze frei.

[39:52] Jetzt sind auf einmal 25 Plätze frei.

[39:54] So, das kann ja nicht.

[39:55] Das heißt, während die Transaktion abläuft, kriege ich unterschiedliche Ergebnisse bei der gleichen Abfrage.

[40:00] Und das ist keine gute Sache.

[40:02] Dadurch können sich dann auch Fehler einschleichen, logischerweise.

[40:05] Und jetzt haben wir das letzte, das ist das Phantom Read, also ein Phantomlesen. Da werden

[40:11] Datensätze gelesen, die es quasi gar nicht gibt. Ein Phantom, ein Phantom-Datensatz. Beispiel,

[40:16] während einer Transaktion, auch hier geht es wieder darum, dass ich Datensätze lese und die

[40:21] lese ich jetzt nach einem bestimmten Kriterium. Beispiel, ja, hatte ich glaube ich eben schon.

[40:25] Ich will die Gehälter lesen von meinen Mitarbeitern. Ich lese alle Gehälter aus meiner

[40:29] Mitarbeiter-Tabelle aus, also sowas wie Select Gehalt from Mitarbeiter zum Beispiel. Ich lese

[40:34] nur das Gehalt wäre ein Kriterium. Und jetzt wird, während ich das lese, eine andere Transaktion

[40:39] diese Liste verändern. Die fügt zum Beispiel einen neuen Mitarbeiter hinzu oder ein Mitarbeiter

[40:44] wurde gekündigt und er wurde gelöscht. Dann habe ich jetzt Gehälter gelesen, ja, aber während ich

[40:49] das lese, fügt eine andere Transaktion was hinzu. Und das führt jetzt dazu, dass ich bei einem

[40:54] sogenannten Phantom Read lese. Stellen wir uns das einmal vor. Ich möchte das Durchschnittsgehalt

[41:01] meiner Mitarbeiter ermitteln. Dazu muss ich erst mal, also ich muss zwei Sachen machen. Erst mal

[41:05] die Summe aller Gehälter ermitteln und dann die Anzahl der Gehälter und das Ganze dann

[41:10] durcheinander teilen, ja. Also erst mal die Summe der Gehälter und dann wie viele Mitarbeiter habe

[41:14] ich und dadurch teile ich das jetzt. Das wären zwei separate Operationen. Einmal Select Sum from

[41:19] irgendwas und Select Count from irgendwas. Angenommen, ich mache beim Select Sum die Gehälter

[41:25] und habe 27 Mitarbeiter. Und während das jetzt läuft, fügt eine andere Transaktion einen weiteren

[41:32] Mitarbeiter hinzu. Dann sind es auf einmal 28. Und wenn jetzt in meiner Transaktion das zweite

[41:37] Select durchgeführt wird, nämlich das Select Count, dann kriege ich nicht mehr die 27 zurück,

[41:41] sondern die 28. Das bedeutet, ich habe beim Ermitteln der Summe der Gehälter 27 Gehälter

[41:47] addiert, beim Ermitteln der Anzahl aber 28 Mitarbeiter ermittelt. Und dann teile ich das

[41:53] Gehalt von 27 Mitarbeitern durch 28 und komme natürlich auf ein falsches Ergebnis, weil

[41:58] zwischendrin irgendwer rumgewirkelt hat. Und das ist der Phantom Read, weil der neue Mitarbeiter,

[42:06] der gerade angelegt wurde, der ist ja in der ersten Abfrage gar nicht drin, in der zweiten

[42:12] aber schon. Also ein Phantom ist aus dem Nichts erschienen quasi. Und das ist eine schlechte Idee.

[42:17] So, wenn wir jetzt diese vier Sachen nochmal unseren Transaktions-Isolationsebenen zuordnen,

[42:22] dann kann bei dem Read Uncommitted, der schlechtesten Ebene, im Prinzip alles davon

[42:27] auftreten. Also alle vier Fehler können auftreten. Wer damit leben kann, schön,

[42:31] ansonsten sollte ich das vielleicht nicht machen. Andersherum bei dem Serializable,

[42:34] bei der härtesten Stufe, kann nichts davon auftreten, weil es wird ja immer alles abgearbeitet

[42:40] und danach ist erst die nächste Transaktion dran. Das heißt, keines dieser Probleme kann

[42:43] auftreten. Bei der zweiten Stufe, dem Read Committed, können jetzt aber Non-Repeatable Read

[42:49] und Phantom Read auftreten, weil dort werden Schreibsperren gesetzt, aber keine Lese-Sperren.

[42:55] Das heißt, ich kann munter lesen, während die Daten noch verändert werden und das führt genau

[43:00] zu dem Non-Repeatable Read, also beim zweiten Lesen kommt was anderes zurück, oder dem Phantom Read,

[43:04] wo zufällig ein Mitarbeiter noch ergänzt wurde. Weil ich eben keine Lese-Sperre habe,

[43:10] kann das auftreten. Aber die anderen Sachen, Dirty Read und Lost Updates, kann nicht passieren,

[43:15] weil für das Schreiben wird das ja gesperrt. Dann das Repeatable Read, die dritte Stufe. Da

[43:21] werden Lese- und Schreibsperren benutzt und da können nur noch Phantom Reads auftreten. Warum?

[43:29] Weil dabei zwei lesende Operationen mit unterschiedlichen Kriterien durchgeführt

[43:34] werden. Wir hatten ja gerade das Beispiel Mitarbeiter, Gehalt, Durchschnitt. Da wird

[43:38] einmal das Gehalt summiert und dann werden die Mitarbeiter gezählt. Das sind ja zwei

[43:43] unterschiedliche Kriterien. Also ich lese einmal die Spalte Gehalt und einmal zähle ich die

[43:48] Mitarbeiter. Das sind zwei unterschiedliche Sachen. Das heißt, die Selects sehen auch

[43:52] unterschiedlich aus. Das sind ja zwei unterschiedliche Statements, kann man sich so vorstellen. Und die

[43:57] Lese- und Schreibsperren sorgen halt nur dafür, dass die gleichen Abfragen das gleiche Ergebnis

[44:02] geben. Das heißt, wenn ich zweimal hintereinander das Gehalt summieren würde, würde auf der Stufe

[44:07] immer das Gleiche zurückkommen. Aber das mache ich ja nicht, denn ich summiere einmal das Gehalt

[44:11] und dann zähle ich die Mitarbeiter. Das ist eine andere Abfrage und das würde dann auf dieser Ebene

[44:16] nicht sichergestellt. Deswegen könnte das Phantom Read noch auftreten, aber das Non-Repeatable Read

[44:22] nicht. Denn Gehalt summieren, da wird definitiv immer das Richtige zurückkommen. Das stellt die

[44:26] Datenbank sicher, aber das Phantom Read kann halt trotzdem noch auftreten. Das wäre die Zusortierung

[44:32] der möglichen Maßnahmen, um die Isolation zu wahren und der möglichen Fehler, die dabei

[44:36] auftreten können. Und jetzt kommen wir zum nächsten Punkt, und zwar der Umsetzung von Transaktionen in

[44:41] SQL. So, kurzer Reminder zum Einstieg. SQL, die Structured Query Language, das ist ja so die

[44:47] Standardsprache, mit der wir relationale Datenbanken abfragen, seit zig Jahren im Einsatz. Eben auch

[44:52] wirklich ein Standard, standardisiert. Und die SQL kann man unterteilen in fünf Familien,

[44:59] Untergruppen, Statementgruppen, wie auch immer man das nennen will. Und eine davon ist die TCL,

[45:05] die Transaction Control Language. Das heißt, schon auf der obersten Ebene wird in SQL eine

[45:12] Untergruppe von Statements nur für die Transaktionssteuerung definiert. Das sollte

[45:17] ausreichend sein, um zu zeigen, wie wichtig die Transaktionen sind, auch im Kontext von SQL.

[45:23] Sicherlich hast du schon mal irgendwo SQL gesehen, benutzt, wenn du mit Datenbanken gearbeitet hast.

[45:28] Und vielleicht hast du die Statements für die Transaction Control Language noch gar nicht so

[45:32] oft benutzt, weil, das nehme ich mal kurz vorweg, viele Datenbanken, zum Beispiel MariaDB, MySQL,

[45:37] normalerweise, wenn du es nicht anders konfigurierst, ein sogenanntes Autocommit nutzen.

[45:42] Das heißt, da wird jedes Statement, was du absetzt, automatisch in einer Transaktion ausgeführt und

[45:47] du musst dich gar nicht darum kümmern, die zu starten, zu beenden, eventuell zurückzurollen

[45:51] und sonst irgendwas. Da wird jedes einzelne Statement, das ist ganz wichtig, also mach

[45:56] nicht automatisch irgendwelche coolen Klammern um deine Aktion, sondern jedes einzelne Statement

[46:00] ist quasi Teil einer Transaktion und wird dann sofort nach dem Absenden persistiert,

[46:05] nach den Asset-Prinzipien. Und dieses Autocommit, das kann man aber bei solchen Datenbanken auch

[46:10] einfach abschalten mit einem kurzen Befehl und dann kann man explizit die Transaktionssteuerung

[46:14] machen. Andere Datenbanken machen sowas nicht von alleine, da muss man wirklich von Anfang an

[46:18] die Transaktionssteuerung nutzen, kommt immer darauf an. Und deswegen guck da gerne in die

[46:22] Doku deiner präferierten Datenbank, ob du das selber machen musst oder ob die Datenbank das

[46:27] von alleine macht bzw. wenn sie es von alleine macht, ist es ja vielleicht nicht unbedingt das,

[46:30] was du willst. Denn dieses Autocommit bei einer Banktransaktion, das wäre halt ätzend,

[46:35] weil dann würde nach dem ersten Update schon eine Transaktion stattfinden und wenn die Datenbank

[46:39] dann die Grätsche macht, ja, dann ist das Ding halt festgeschrieben. Also gar keine so gute Idee,

[46:44] dieses Autocommit, wenn du eine größere Transaktion starten willst. Dann musst du es manuell machen,

[46:49] weil du sonst jedes einzelne Statement sofort persistiert hast und das willst du nicht. Also,

[46:53] Hinweis, Autocommit, vielleicht nicht so eine gute Sache, sollte man dann ausschalten. So und

[46:58] jetzt kommen wir aber zu den, eigentlich sind es drei oder es sind drei Statements der SQL,

[47:03] die die TCL bilden und zwar ist das BeginTransaction, Commit und Rollback. Das sind so die drei,

[47:10] die man benutzen muss oder sollte, wenn man Transaktionen starten möchte. Überraschung,

[47:16] das ist BeginTransaction, ja, das startet eine Transaktion und nach diesem Statement kannst du

[47:21] dann deine anderen SQL Statements ausführen, die du halt ausführen wolltest im Rahmen der

[47:25] Transaktion und wenn du fertig bist, hast du zwei Möglichkeiten. Entweder du sagst Commit und Commit

[47:30] beendet dann die Transaktion und schreibt die Änderungen fest. Commit kennst du vielleicht auch

[47:34] im Kontext von Git, Versionsverwaltung, machst den Commit am Ende und dann wird das festgeschrieben.

[47:38] Bei Git schreibt er die Änderungen, also den Commit in die Local History, in der Datenbank,

[47:42] wird das halt dann in der Transaktion in die Datenbank überführt und dort persistent

[47:46] abgelegt. Wenn du aber sagst, will ich doch nicht haben, ich will das Ding wieder zurückdrehen,

[47:51] also ich will die Transaktion rückgängig machen, dann ist die Entsprechung dafür das Rollback.

[47:56] Das heißt, ja, wie sieht so ein Befehl aus? Transaktionssteuerung, BeginTransaction,

[48:00] mach irgendwas und dann kommt Commit oder BeginTransaction, mach irgendwas und dann entscheidest

[48:04] du dich, soll alles wieder weg, dann machst du ein Rollback und dann wird alles zurückgerollt

[48:08] bis zum Start der Transaktion. Das macht dann die Datenbank. Also, diese drei Statements,

[48:13] BeginTransaction, Commit, Rollback, das ist die TCL, mit der du Transaktionen steuern kannst

[48:20] über SQL in deiner relationalen Datenbank. So, wenn du also mit SQL die Transaktionen

[48:26] steuern kannst, dann wird es ja auch irgendwie eine Möglichkeit geben, dass, ob ich das cooler

[48:33] machen kann oder wie wollte ich eigentlich sagen, aber ist ja eigentlich Quatsch, also ich wollte

[48:36] noch ein kleines Minikapitel einschieben für alle Softwareentwickler und Entwicklerinnen da draußen,

[48:39] die jetzt sagen, boah, SQL, ey, das benutzt ja seit den 80ern keiner mehr, wir haben nur heute

[48:44] ORMs, wir haben so coole Frameworks, ob sie jetzt, weiß nicht, Spring Boot ist oder Quark ist oder

[48:49] .NET oder irgendwas, da mach ich doch gar nichts mehr mit der Datenbank. Das macht einfach die

[48:53] Software. Ich mach CodeFirst, ich interessiere mich null für die Datenbank, ich code einfach

[48:58] was runter und ja, die Datenbank ist so ein Abfallprodukt, am Ende kommt die halt einfach

[49:02] raus. Und das hört sich jetzt so blöd an, aber ganz ehrlich, ich entwickle ja auch so keine,

[49:07] ich wollte schon sagen, keine Sau, interessiert sich für die Datenbank, ist natürlich nicht

[49:10] richtig, aber wenn ich CodeFirst arbeite, ist die Datenbank tatsächlich ein Abfallprodukt. Ich

[49:15] interessiere mich wirklich gar nicht erst dafür, wie die Tabellen heißen, wie die Schlüssel sind

[49:19] und ob das alle funktioniert, ist mir eigentlich egal, weil das macht ja das Objektrelationale

[49:24] Mapping für mich. In Java zum Beispiel Hibernate oder das Entity Framework in .NET oder ehrlich

[49:30] gesagt für andere Sprachen kenne ich die Namen nicht, aber es gibt eigentlich für jede Sprache

[49:33] oder sonst irgendwelche ORMs, die mir genau diese Übersetzung meiner Objektorientierung in die

[49:39] relationale Welt abnehmen. Und dann sage ich einfach Save und dann ist das Zeug in der Datenbank. Und

[49:45] noch besser, wenn ich eine Klasse anlege und dann ein paar Annotationen zum Beispiel in Java

[49:48] dran schreibe, dann wird die Tabelle dafür automatisch erzeugt. Ich muss mich gar nicht

[49:52] darum kümmern, wie die Datentypen sind und wie das gespeichert wird und die Sachen wieder rauszuholen

[49:56] und M2N-Beziehungen und Schlafmilchto. Das macht ja alles das ORM. Also warum soll ich mich über

[50:01] Transaktionen irgendwie unterhalten? Was bringt mir das? Macht das ORM doch für mich. Habe ich

[50:05] mich noch nie mit beschäftigt. So, könnte man jetzt sagen. Aber da finde ich es mal ganz wichtig,

[50:11] ich will ORMs nicht schlechtreden. Auf gar keinen Fall. Ich benutze die selber jeden Tag und ich

[50:15] finde die super. Die machen einen viel, viel produktiver, als wenn man das alles selber

[50:18] machen müsste, selber programmieren müsste und Gott bewahre SQL schreiben müsste. Das möchte

[50:23] ja keiner. Dafür haben wir ja die ORMs. Alles gut. Das Ding ist nur, man sollte vielleicht auch

[50:26] verstehen, was die einem für Arbeit abnehmen. Denn wenn die mal nicht richtig funktionieren,

[50:31] dann sollte man wissen, was eigentlich unter der Haube passiert, um den Fehler vielleicht

[50:35] beheben zu können oder es richtig machen zu können. Das gilt auch für Transaktionen. Also

[50:40] nur weil ich ein ORM habe, heißt das nicht, dass ich nicht wissen muss, was eine Transaktion ist.

[50:44] Oder noch viel schlimmer, dass ich fachlich nicht wissen muss, was eigentlich zu einer Transaktion

[50:48] zusammengefasst werden muss und was nicht. Ich kann nicht, wie wir das Auto-Commit eben einmal

[50:53] gehört haben, in der Datenbank sagen, alles was ich in der Datenbank mache, wird sofort gespeichert.

[50:57] Das ist ja keine vernünftige Programmierung. Denn hoffe ich, wenn du Software entwickelst,

[51:01] wirst du auf jeden Fall auch immer an den Fehlerfall denken. Es läuft halt nicht alles

[51:05] glatt im Leben und gerade wenn wir eine verteilte Anwendung haben, in der Datenbank auf einem anderen

[51:08] Server als meine Web-Anwendung zum Beispiel, da kann auch mal das Netzwerk weg sein, das kann

[51:12] langsam sein, da kann irgendwie, ich weiß nicht, gibt es ein Timeout oder sonstige Sachen. Das

[51:17] heißt, ich kann nicht einfach so tun, als würde das immer heile Welt sein und immer laufen. Das

[51:21] heißt, ich brauche eine Fehlerbehandlung und Fehlerbehandlung sieht nicht so aus, speichere

[51:24] alles in der Datenbank, das war's. Sondern wenn du schon die Hälfte gespeichert hast und dann

[51:29] tritt ein Fehler auf, dann sollte diese kaputte Hälfte aus der Datenbank vielleicht auch wieder

[51:32] rausfliegen. Und wie können wir das machen? Überraschung, Transaktionen. Denn genau dafür

[51:36] sind die da. Das heißt, OEMs entbinden dich nicht davon, auch ein bisschen was von der Datenbank

[51:41] darunter zu verstehen und vor allem das Prinzip von Transaktionen, das wirst du eins zu eins auch

[51:46] in deinem OEM irgendwie wieder umsetzen müssen, weil das macht das OEM nicht von alleine. Das

[51:52] OEM kann dir ganz viel abnehmen, um mit der Datenbank zu reden. Das OEM kann dir nicht die

[51:55] fachlichen Entscheidungen abnehmen, welche Daten gemeinsam persistiert werden müssen oder nicht.

[52:00] Das ist deine Aufgabe, beziehungsweise die des Fachbereichs oder wer auch immer das festlegt,

[52:04] aber das macht nicht das OEM. Das OEM ist nur ein Tool und dem musst du schon sagen,

[52:07] was es tun soll und wie es richtig aussehen muss für die Daten, die du da persistierst.

[52:13] So und jetzt gibt es verschiedene Möglichkeiten, wie das dann in den OEMs gelöst ist. In irgendeiner

[52:18] Form willst du einen Syntax geben mit dem OEM, mit dem du arbeitest, um dort zu sagen,

[52:23] starte eine Transaktion oder fasse alles, was jetzt passiert, in eine Transaktion zusammen oder

[52:27] rolle eine Transaktion zurück oder sonstiges. Das kann ich jetzt nicht für alle sieben,

[52:31] drölfzig verschiedenen OEMs, die es für alle möglichen Sprachen gibt, da draußen sagen. Das

[52:35] musst du dann einfach mal rausbekommen. Ich habe jetzt mal nur ein Beispiel mitgebracht. Ich bin

[52:39] ja selber im Java-Umfeld unterwegs und da gibt es ja Jakarta EE als Enterprise Edition von Java

[52:44] und da gibt es eine eigene Spezifikation, die heißt JTA, die Jakarta Transactions und das ist

[52:51] ein einzelner Teil der Java oder Jakarta EE Specification, die sich ausschließlich um

[52:57] Transaktionssteuerung drehen. Und um das mal so ein bisschen ins Verhältnis zu setzen, das OEM,

[53:02] was ich in Jakarta EE benutze, das JPA, die Java Persistence API oder die Java Server Faces,

[53:08] das UI, das sind auch einzelne Spezifikationen. Das heißt, der Datenbankzugriff oder die

[53:16] grundsätzliche Gestaltung einer Oberfläche spielen in der gleichen Liga wie die

[53:20] Transaktionssteuerung. So wichtig ist das, dass es dafür einen eigenen Standard gibt. Das heißt,

[53:25] man kann also nicht sagen, ich nutze Jakarta EE, ich kümmere mich nicht um die Datenbank,

[53:28] mir doch egal, Transaktionen interessieren mich nicht. Nee, das ist nicht der Fall. Du musst die

[53:33] Entscheidung treffen, was muss Teil einer Transaktion sein und was nicht. Und um es kurz

[53:38] mit dem Beispiel zu vervollständigen, in Jakarta EE kann ich dann halt zum Beispiel an meine Java

[53:42] Methode, ich programmiere eine ganz normale Methode, die da irgendwie, weiß ich nicht,

[53:46] drei Sachen in der Datenbank speichert zum Beispiel, mit JPA dann zum Beispiel, dann kann

[53:50] ich die Annotation addTransactional an diese Methode dran schreiben und JTA, die Jakarta

[53:57] Transactions, die werten das dann aus und das ist dann das sogenannte Transaction Around Pattern.

[54:02] Das gibt es sogar als Design Pattern, nicht als klassische Design Pattern, wie es im Buche steht,

[54:07] aber als Design Pattern, wie ich meinen Code gestalten kann, um nicht bei jedem möglichen

[54:12] Kram, den ich mit der Datenbank mache, immer an die Transaktionen denken zu müssen, sondern da sage

[54:17] ich einfach, ich programmiere ganz normal, straightforward meine Methode runter, speichere

[54:21] das, update das, lösche das und lese das und dann sage ich am Ende Transaction Around, um

[54:26] dieses ganze Zeug herum möchte ich eine Transaktion haben. Die soll vorher gestartet werden und die

[54:30] soll am Ende beendet werden und wenn es einen Fehler gibt, das ist das, was die Geschichte mir

[54:35] dann auch noch abnehmen kann, dann soll das Ding automatisch zurückgerollt werden. In Java als

[54:39] Beispiel fliegt eine Exception irgendwo beim Speichern, dann wird das ganze Zeug wieder

[54:43] zurückgerollt und das will ich nicht händisch programmieren, wenn du ein bisschen Java kennst,

[54:47] ich müsste jetzt sowas wie ein try-catch-finally machen und im Catchblock wird dann alles

[54:51] zurückgerollt und solche Sachen. Das ist enorm viel Code, den ich in jeder Methode fast identisch

[54:57] habe, die irgendwas mit der Datenbank machen und deswegen gibt es dieses Pattern Transaction

[55:00] Around. Ich programmiere einfach meine Methode runter und dann sage ich am Ende, in diesem Fall

[55:05] mit einer Annotation, die ich vor die Methode schreibe, das ist ein Wort, addTransactional und

[55:09] dann sorgt das Framework dafür, dass bevor die Methode aufgerufen wird, eine Transaktion gestartet

[55:15] wird und am Ende der Methodenausführung wird die Transaktion beendet und wenn irgendwo dazwischen

[55:20] eine Exception fliegt, dann macht es automatischen Rollback. So ungefähr kann man sich das vorstellen.

[55:24] Es spart mir also, weiß ich nicht, acht Zeilen Code pro Methode, indem ich einfach diese Annotation

[55:29] dran schreibe. Das entbindet mich aber nicht davon zu entscheiden, dass eine Methode in einer

[55:34] Transaktion ausgeführt werden muss, weil das kann JTA auch nicht wissen. JTA bietet mir nur die

[55:38] Möglichkeit an, das dahin zu schreiben, aber ob das da stehen muss, weiß es nicht. Das muss ich

[55:43] schon selber machen. Das heißt, die Idee, was muss in einer Transaktion, brauche ich überhaupt eine

[55:49] Transaktion, das muss weiterhin du als Softwareentwickler oder Entwicklerin entscheiden

[55:53] und dann gibt es dafür Frameworks, die in diesem Fall sogar zusätzlich zum ORM oder sogar da auch

[56:00] integriert angeboten werden, damit du es etwas einfacher hast. Aber ich fasse nochmal kurz

[56:05] zusammen, als Softwareentwickler, als Softwareentwicklerin, auch wenn ich ORMs benutze oder

[56:08] irgendeine andere Abstraktion über die Datenbank, ich muss mich mit Transaktionen auseinandersetzen

[56:13] und ich muss mal in die Doku gucken, wie mein Tool Transaktionen handelt, damit ich das korrekt

[56:18] umsetzen kann. Also wichtiges Thema für uns alle. So, jetzt habe ich zum Abschluss der Episode noch

[56:24] ein ganz anderes Thema. Wir haben jetzt viel über Transaktionen und Asset geredet, alles

[56:26] prüfungsrelevant, aber noch viel wichtiger, praxisrelevant. In jeder Anwendung da draußen

[56:31] werden wir wahrscheinlich irgendwann früher oder später irgendwas mit Transaktionen machen müssen,

[56:34] vermutlich. Außer du hast eine echt super billige Crud-Applikation oder so. Aber gut, wie dem auch

[56:39] sei. Sogar bei der Entwicklung brauchen wir es, selbst bei ORMs, habe ich jetzt alles gesagt. Aber

[56:43] es gibt auch noch, ja, wie soll ich sagen, eine Art Gegenentwurf zu diesen Transaktionen bzw. zu

[56:49] den Asset-Prinzipien. Denn in der heutigen Welt, ich nehme das hier 2024 auf, ja, aber die heutige

[56:55] Welt gibt es auch schon seit 10 Jahren oder 20 Jahren, seit ich das aufnehme, und zwar die Welt,

[57:00] in der wir im Internet verteilte Anwendungen haben, vielleicht sogar verteilte Datenbanken

[57:05] haben. Und da wird es dann richtig interessant bei diesen Asset-Prinzipien, denn dafür sind die so

[57:10] gar nicht gemacht. Beispiel, ich habe eine verteilte Datenbank. Oder nehmen wir ein ganz

[57:14] einfaches Beispiel. Ich habe zwei Knoten, ja. Das heißt, ich habe nicht einen einzigen dicken,

[57:17] fetten Datenbank-Server, wo alles drauf ist, sondern ich habe zwei dicke, fette Datenbank-Server.

[57:21] Und weil das sonst so langsam ist, steht einer davon in Amerika und der andere steht in Europa,

[57:25] zum Beispiel, ja. Und diese Datenbank-Server sollen sich untereinander abgleichen. Das heißt,

[57:29] wenn ich in Amerika eine Anfrage stelle, soll das Gleiche herauskommen wie in Europa. Würde ich

[57:33] jetzt erstmal erwarten. Nur damit es dann schneller ist, sind die ein bisschen anders

[57:36] verteilt. Das heißt, die Datenbanken müssen sich untereinander synchronisieren. Man sagt dann auch,

[57:41] die müssen sich replizieren. Wenn ich zum Beispiel ein Update mache auf Server A,

[57:45] dann soll automatisch auch auf Server B das Datum aktualisiert werden, logischerweise. Das haben wir

[57:50] in unterschiedlichen Datenstand. Und da kommen wir jetzt in ein leichtes Problem, denn wenn ich jetzt

[57:55] so ein Asset-Modell habe und in meiner Datenbank in Amerika mache ich ein Update, dann erwartet das

[58:02] Asset ja, dass nach dieser Transaktion die Daten in einem konsistenten Zustand sind und zwar auf

[58:08] allen Knoten verteilt gleich sind. Sonst hätte ich in Amerika die Transaktion abgeschlossen,

[58:13] aber der Server in Europa weiß das noch gar nicht. Und jetzt frage ich den in Europa ab und er gibt

[58:17] mir ein anderes Ergebnis als der in Amerika. Das wäre irgendwie uncool, oder? Dann habe ich ja

[58:20] inkonsistente Daten zwischen Amerika und Europa und das wollen wir nicht. Aber das wäre jetzt

[58:27] halt so, wenn wir das Asset aufbrechen würden. Deswegen darf man das natürlich nicht. Und jetzt

[58:33] müssen wir, wenn ich in Amerika ein Update mache, so lange warten, bis die Replikation mit Europa

[58:38] fertig ist. Das heißt, ich warte jetzt nicht nur darauf, dass die Datenbank in Amerika ihre

[58:42] Transaktion mal schön zum Beispiel in das Transaktions-Log geschrieben hat, sondern ich

[58:46] muss auch noch darauf warten, dass dieser Server sich mit dem in Europa abgeglichen hat, also das

[58:49] einmal um die Welt geschickt hat das Zeug und der das dann auch noch abgespeichert hat. Das heißt,

[58:54] meine ändernden Zugriffe auf die Datenbank werden extrem langsam, weil ich muss nicht mehr nur auf

[58:58] einen Server warten, der es speichert, sondern auf mehrere. Und wenn die jetzt auch noch so

[59:02] verteilt sind, dass die Kommunikation dazwischen langsam ist, zum Beispiel übers Internet, dann

[59:05] brauche ich auf einmal, weiß ich nicht, Sekunden oder, wenn es ganz schlecht läuft, Minuten, um

[59:10] irgendwas in der Datenbank zu speichern. Und das ist kein guter Zustand. Das heißt, dieses Asset-Modell,

[59:15] das funktioniert für eine einzige Datenbank, die ich bei mir lokal im Keller habe, wunderbar. Dann

[59:20] weiß ich, das Ding ist immer konsistent. Alles klar, das mache ich so. Fange ich aber an, meine

[59:24] Datenbank zu verteilen.

[59:26] dann wird das ein Problem. So, jetzt bin ich ganz ehrlich, ich will jetzt, bin nicht auf dem Trichter zu sagen, wir haben, wir arbeiten alle bei Netflix, Amazon, Microsoft, wie auch immer und haben alle Applikationen mit 700 Knoten-Datenbanken, die verteilt sind um die ganze Welt, also wir müssen es nicht übertreiben, ja, die wenigsten von uns arbeiten in solchen Konzernen und ich würde jetzt einfach mal aus dem Bauch heraus behaupten, 80, 90 Prozent der Anwendungsentwickler und Entwicklerinnen arbeiten nicht bei solchen Riesenkonzernen, sondern so wie ich zum Beispiel in einer kleinen Versicherung, wo wir alles bei uns lokal haben, es gibt einen Datenbank-Service,

[59:56] aber unfettig und da muss ich mich um solche Probleme wie verteilte Datenbanken überhaupt nicht kümmern, denn es gibt keine verteilte Datenbank und es gibt auch überhaupt gar keinen Use-Case dafür, die einzuführen, ja, sondern wir haben alle, zum Beispiel jetzt bei uns, wir sind zwar um die 300 Leute, aber wir haben, ich übertreibe jetzt mal, wir haben einen Server, da läuft alles drauf, die schöne, dicke, alte Oracle-Datenbank und da ist halt alles drin, ja, und das funktioniert auch, das ist performant, das können wir super einfach backupen, es gibt kaum Ausfälle, alles toll, ja, also warum sollten wir jetzt einen zweiten Knoten daneben stellen, um eine verteilte

[1:00:27] Anwendung zu bauen, das brauchen wir einfach nicht, ja, und viele, viele, viele andere Unternehmen brauchen das auch nicht, weil sie nur Software für sich selber entwickeln und nicht für Millionen Kunden weltweit, die alle um 8 Uhr gleichzeitig einen Film streamen wollen, das ist einfach für viele Anwendungsentwicklerinnen und Anwendungsentwickler völlig irrelevant, ja, trotzdem sollten wir uns ja damit auseinandersetzen, was man denn tun müsste, wenn man so eine Anforderung mal hat, ja, und das kann ja auch mal ganz schnell gehen, angenommen, ich mache irgendwie einen kleinen Internetshop auf oder so und habe jetzt Kunden, die weltweit verteilt sind,

[1:00:55] dann wäre es vielleicht schon mal irgendwann anzuraten, eine verteilte Anwendung um die Welt zu verstreuen, damit ich schneller Antwortzeiten bekomme, da muss ich gar nicht so groß sein, ne, in Zeiten des Internets, Kunden können von überall auf der Welt kommen, dann kann das eine Anforderung werden oder wenn ich zum Beispiel Cloud-Infrastruktur habe, da ist es vielleicht sogar schon fast eingebaut, dass ich verteilte Anwendungen habe und so, also, heißt jetzt nicht, dass man das jetzt alles nicht kennen und können muss, was ich jetzt erzähle, aber ich behaupte, dass es viele normale, in Anführungszeichen, Programmierer oder Anwendungsentwicklerinnen und Anwendungsentwickler

[1:01:25] draußen kein großer Use-Case ist, eine verteilte Datenbank aufzumachen, aber wenn doch, dann kriegen wir da genau das Problem, was ich gerade gesagt habe, dann sage ich nämlich dem Server in Amerika, speichere mal meine Daten und warte drei Minuten, bis er fertig ist, weil der auch noch dem Server in China und in Europa und in Australien erstmal sagen muss, dass er das auch noch speichern soll und wartet, bis alles fertig ist, ja, und was passiert denn dann, wenn der Server in Europa gerade vom Netz genommen wurde?

[1:01:48] Dann haben wir ein Riesenproblem, weil dann haben drei Knoten das Update gekriegt, aber der vierte nicht, das funktioniert nicht, dann wird alles zurückgerollt, dann kann ich das nicht speichern, oh, das ist alles schlecht, ja, das heißt, in solchen verteilten Szenarien ist ACID keine gute Idee, ja, weil das führt dann dazu, wenn wir es umsetzen, quasi wie es im Buche steht, dann haben wir zwar weltweit einen konsistenten Datenstand, aber das kann extrem langsam werden oder wenn ein Knoten zum Beispiel ausfällt, fällt das gesamte System aus, weil das System das nicht mehr abkriegt.

[1:02:19] Wenn der letzte Knoten es nicht aktualisieren kann, weil wir einen inkonsistenten Zustand haben, ja, und aus dieser Erklärung, die ich jetzt hier gerade einfach mal so nebenbei gemacht habe, hat dann ein schlauer Mensch mal das sogenannte CAP Theorem abgeleitet.

[1:02:33] Das sind nämlich genau die drei Sachen, die ich gerade erklärt habe. CAP steht für Consistency, also die Konsistenz, die Availability, die Verfügbarkeit und die Partition Tolerance, also die Partitions- oder Ausfalltoleranz, also konsistente Daten, Verfügbarkeit der Daten und Ausfalltoleranz.

[1:02:53] Das sind die drei Sachen, die das CAP Theorem quasi in so einer Art Dreieck anordnen und jetzt ist das so ein bisschen wie beim magischen Dreieck im Projektmanagement, Qualität, Kosten und Zeit, wähle zwei und genauso ist es beim CAP Theorem, ich kann niemals alle drei gleichzeitig umsetzen und das ist eine Theorie, die sich auf verteilte Systeme bezieht.

[1:03:13] Also wir reden jetzt nicht mehr von einer einzigen Datenbank, die im Keller steht, sondern wir müssen eine verteilte Anwendung haben, damit das Anwendung findet und dann kann ich mich entscheiden, will ich Konsistenz, Verfügbarkeit oder Ausfallsicherheit oder Ausfalltoleranz heißt es, Entschuldigung, und davon kann ich zwei auswählen und das dritte ist automatisch nicht erfüllt.

[1:03:32] Aus der Geschichte, die ich gerade erzählt habe, kann man das sogar selbst so ein bisschen herleiten. Ganz wichtig nochmal, bevor wir da weiter einsteigen, diese Konsistenz, die C, Consistency, das ist jetzt ein bisschen was anderes als das C aus ACID, das ist ein Problem, denn bei ACID steht es auch für Consistency, da ist aber gemeint die Konsistenz der Daten innerhalb der Transaktionen, beziehungsweise innerhalb der einen Datenbank vor und nach der Transaktion.

[1:03:56] Also jetzt mal ganz blöd gesagt, dass ich die beiden Updates bei der Banküberweisung auch gemacht habe, dass nicht Geld aus dem Nichts entstanden ist, das war da die Konsistenz. Hier ist die Konsistenz gemeint mit dem Abgleich der Daten zwischen den verschiedenen Datenbankknoten, also mein Beispiel eben amerikanischer Server, europäischer Server, dass die den gleichen Datenstand haben.

[1:04:16] Wir sind hier auf einem deutlich höheren Abstraktionsniveau als bei dem C aus ACID. Da geht es um ein, zwei Statements, die korrekt gelaufen sind. Hier geht es darum, dass mehrere Server, die irgendwo verstreut sind, insgesamt den gleichen Datenstand haben. Das ist hier mit der Konsistenz gemeint, also bitte nicht durcheinander bringen.

[1:04:34] So und jetzt haben wir diese drei Sachen, also Konsistenz heißt, dass über alle Datenbankknoten hinweg ein einheitlicher Datenstand gewährleistet ist und egal welchen Knoten ich frage, ich kriege immer die gleiche Antwort. Egal ob ich Amerika frage oder Europa, es kommt zu jedem Zeitpunkt die gleiche Antwort zurück und nicht mal so und mal so. Das ist jetzt Konsistent.

[1:04:56] Dann haben wir die Verfügbarkeit, die Availability. Das bedeutet, dass die Datenbank grundsätzlich auch antwortet, wenn ich sie frage. Das heißt, das dauert nicht fünf Minuten, bis ich eine Antwort kriege oder ich kriege gar keine Antwort, also sie ist zum Beispiel down oder gar nicht erreichbar, sondern ich kriege eine Antwort, wenn ich frage.

[1:05:12] Und das ist jetzt schon das erste Problem im Zusammenhang mit Konsistenz. Es kann jetzt hier sein, dass ich nicht immer die gleiche Antwort kriege. Das heißt, die Datenbank ist grundsätzlich verfügbar, aber wenn ich zum Beispiel Amerika frage statt Europa, kann es sein, dass ich unterschiedliche Daten zurückgeliefert bekomme, weil der Datenstand nicht konsistent ist. Das ist so ein bisschen schon mal die erste Abgrenzung, Availability gegenüber Consistency.

[1:05:37] Und dann haben wir noch das dritte, die Partition Tolerance, also die Partitionstoleranz oder Ausfalltoleranz. Das heißt, die Datenbank arbeitet auch dann weiter, wenn einzelne Knoten ausfallen. Und ausfallen muss es nicht heißen, dass da irgendwie die CPU durchbrennt, kann auch einfach sein, dass das Netzwerk mal weg ist. Server wird gerade runtergefahren, es wird gepatcht, wird gewartet, was auch immer. Netzwerk ist langsam oder so, kann ja auch sein. Dann arbeitet die Datenbank insgesamt aber trotzdem weiter, auch wenn ein Knoten nicht mehr erreichbar ist.

[1:06:03] Diese drei Sachen, die widersprechen sich jetzt so ein bisschen. Wir wollen jetzt nicht alle verschiedenen Kombinationen durchgehen, warum die sich widersprechen oder sowas. Aber nehmen wir ein Beispiel. Angenommen, ich möchte die Konsistenz und die Verfügbarkeit sicherstellen. Also ich möchte, egal wen ich frage, die gleiche Antwort bekommen. Und ich möchte, dass die Verfügbarkeit gewährleistet ist, also dass ich auch sofort eine Antwort kriege und nicht warten muss.

[1:06:27] Dann heißt das automatisch, dass die Partitionstoleranz wegfällt, denn das bedeutet, wenn ein Knoten ausfällt, muss die ganze Datenbank ausfallen, weil sonst die Konsistenz ja nicht mehr gewährleistet ist. Angenommen, ich habe vier Knoten, ich mache ein Update auf einem der Knoten, der kann aber nur in drei Knoten das Update speichern und der vierte Knoten ist inkonsistent.

[1:06:47] Dann darf die Datenbank das nicht speichern, wenn der vierte Knoten nicht erreichbar ist, weil dann ja per Definition die inkonsistenten Daten die Folge wären. Und das würde bedeuten, ich habe keine Partitionstoleranz mehr, weil es darf kein Knoten ausfallen. Denn sobald ein Knoten ausfällt, kann die Konsistenz nicht mehr gewährleistet sein und dann darf die Datenbank insgesamt auch nicht mehr richtig antworten und auch nicht mehr speichern können.

[1:07:11] Also da sieht man schon in einem einfachen Beispiel, die drei Sachen, die bedingen sich gegenseitig und man kann nicht alle drei erreichen.

[1:07:17] So, das ist das CAP Theorem. Und jetzt haben wir noch ein anderes Akronym und das heißt BASE und da gehen wir jetzt auch noch mal kurz drauf ein.

[1:07:27] So und dieses BASE, das hat sich jemand schlaues ausgedacht und hat da wieder so einen kleinen Wortwitz draus gemacht. IT-ler sind extrem witzig, das kennst du bestimmt. Wir haben so richtig witzigen Humor und so Nerd-Geschichten, die wir da gerne einbauen.

[1:07:39] Und natürlich sind wir alle komplett fit in den Naturwissenschaften und kennen aus der Chemie natürlich den Unterschied zwischen Säure und Lauge. Nicht wahr? Kennst du bestimmt auch aus dem Chemieunterricht. Und die Säure heißt ja auf Englisch ACID und Lauge heißt auf Englisch BASE.

[1:07:59] Das heißt, das ist hier ein Gegenentwurf zu den ACID-Prinzipien, also zu der Säure, hat hier jemand sich die Lauge ausgedacht. Und dann, und das hat glaube ich der Erfinder sogar selber zugegeben, das war jetzt erstmal der Witz, den er machen wollte und dann hat er im Nachhinein so ein bisschen überlegt, was könnte es denn heißen, das BASE.

[1:08:15] Und hat dann da aus diesen vier Buchstaben irgendwie drei Begriffe gemacht, die, also anders als bei ACID, wo jeder Buchstabe einen Begriff hat, hat BASE nur drei Begriffe. Die ersten beiden Buchstaben stehen nämlich für BASICALLY AVAILABLE und dann kommt SOFT STATE und dann kommt EVENTUAL CONSISTENCY. Also B-A-S-E, BASICALLY AVAILABLE, SOFT STATE, EVENTUAL CONSISTENCY.

[1:08:38] Und diese drei Sachen, die stehen so ein bisschen im Gegenentwurf zu diesen ACID-Kriterien. Und hier geht es eben darum, wenn ich eine verteilte Datenbank habe, dass das ACID halt eben nicht mehr funktioniert. Wir haben es uns ja gerade angeguckt, warum das nicht funktioniert. Ich kann nicht bei einer weltweit verteilten Datenbank sicherstellen, dass bei einer Transaktion sofort danach alle Knoten weltweit den gleichen Stand haben.

[1:09:00] Also natürlich ist das möglich, aber es dauert halt und wir haben ja gerade gelernt, wenn dann ein Knoten ausfällt, dann geht das schon wieder alles nicht. Also das ist nicht das, was wir eigentlich haben wollen. Wenn wir eine verteilte Datenbank haben, dann müssen wir anders an die Sache rangehen. Wir können nicht erwarten, dass wir zu jedem Zeitpunkt einen konsistenten Zustand haben, sondern wir müssen einfach davon abweichen.

[1:09:19] Und man kann ganz allgemein sagen, dass das ACID so ein bisschen die Konsistenz eines Systems in den Mittelpunkt stellt und sicherstellen will. Und BASE stellt eher die Verfügbarkeit in den Vordergrund. Und das ist dann bei solchen Anwendungen auch wichtiger. Nehmen wir mal wirklich das klassische Beispiel Netflix. Alle machen ja das, was Netflix macht, weil ich habe ja hier in Kleinfechter bei der Halte Oldenburger muss ich auch 700 parallele Server für Streaming-Dienstleister anbieten.

[1:09:46] Aber egal, Netflix macht es, also müssen wir es auch machen. Im Gegenteil, die kleine Versicherung in Fechter macht eher ACID mit einer dicken fetten Oracle-Datenbank oder läuft das einfach. Netflix, das geht halt ein bisschen anders. Netflix hat weltweit verteilt irgendwelche Kunden, die irgendwie alle parallel gleichzeitig irgendwas machen wollen.

[1:10:03] Und dann ist es denen ehrlich gesagt herzlich egal, ob der Datenbankstand von Netflix weltweit gleich ist. Das interessiert die überhaupt nicht. Das Einzige, was die Kunden interessiert, ist, dass wenn ich jetzt auf Play drücke, der Film anfängt und ich nicht 30 Minuten warten muss, bis weltweit alle Server die Freigabe erteilen, dass ich auf Play drücken kann. Das ist definitiv nicht das, was wir brauchen.

[1:10:22] Das heißt, was die Kunden von Netflix ganz wenig interessiert, ist Konsistenz. Aber was die ganz viel interessiert, ist die Verfügbarkeit. Ich will sofort loslegen und nicht erst, wenn der Server in China sagt, jetzt darfst du aber. Also, da haben wir einfach andere Use Cases. Es ist einfach ein anderer Hintergrund. Ich habe nicht meine dicke fette ACID-Datenbank, sondern ich habe eine verteilte Datenbank.

[1:10:41] Und dann ist es im Zweifel sogar egal, ob der Kunde in England gerade einen anderen Trailer angezeigt bekommt, als der in Amerika oder der in Deutschland. Das jetzt mal als Beispiel, was die Recommendation Engine, die tollsten Filme heute oder sowas. Wenn da unterschiedliche Welten zurückkommen, je nachdem, wo ich gerade bin, who cares? Es interessiert niemanden. Es wird keiner sagen, ich kriege hier aber was anderes angezeigt als der in Amerika. Das merkt niemand und das interessiert auch keinen.

[1:11:08] Aber was die Leute interessiert ist, wenn gar nichts angezeigt wird, weil der Datenbankstand ja konsistent sein muss und die Datenbank sagten, kann ich gerade nicht, also zahle ich gar nichts an. Das ist schlecht. Das heißt, wir haben hier einfach eine andere Anforderung. Wir wollen das Ding verfügbar haben und es ist irrelevant, aber es ist uninteressant, ob das Zeug auch konsistent ist. Also, ganz andere Anforderung. Wenn ich eine verteilte Datenbank habe, dann mache ich die mit BASE und nicht mit ACID.

[1:11:35] Und jetzt gehen wir nochmal in die drei Sachen durch, dann haben wir es für heute. BASICALLY AVAILABLE bedeutet, dass die Datenbank grundsätzlich für alle Benutzer jederzeit erreichbar ist. Also genau das, was wir eigentlich haben wollen gerade, hohe Verfügbarkeit. Und das geht zu Kosten der Konsistenz. Ich kann nicht eine hohe Verfügbarkeit haben und gleichzeitig eine hohe Konsistenz. Das ist einfach nicht möglich, wie gerade jetzt mehrfach erklärt.

[1:11:59] Also, das BASICALLY AVAILABLE, das sagt eigentlich schon fast alles aus. Passt ganz gut. Das sind ja schon zwei von vier Buchstaben in dem Begriff. Damit ist eigentlich schon alles gesagt. Grundsätzlich ist die Datenbank erreichbar, aber liefert vielleicht nicht immer die aktuellsten Daten. Das ist im Prinzip mehr oder weniger BASE zusammengefasst.

[1:12:15] Das SOFT STATE und EVENTUAL CONSISTENCY macht jetzt nochmal ein bisschen deutlicher. SOFT STATE bedeutet, dass ein weicher Zustand der Daten, es gibt keinen harten Fakt, die Datenbank sagt, so und so ist es und dann ist das so. Sondern je nachdem, wie ich die Datenbank abfrage, kann nochmal was anderes zurückkommen, weil es halt noch nicht konsistent.

[1:12:33] Das heißt, SOFT STATE, es gibt eine Art weichen, einen temporären Zustand, den meine Daten annehmen können, wenn gerade parallele Änderungen laufen, zum Beispiel. Das heißt, wie wir bei ACID hatten, die Transaktionen, die sich nicht gegenseitig beeinflussen, das kann bei BASE halt schon mal passieren. Weil, wie gesagt, die Verfügbarkeit steht im Vordergrund und nicht die Konsistenz.

[1:12:53] Also SOFT STATE, es kann so ein bisschen weiche, temporäre Zustände geben und das EVENTUAL CONSISTENCY, das bedeutet, dass irgendwann einmal die Datenbank in einem konsistenten Zustand sein wird. Auch hier bitte nicht falsch verstehen, BASE heißt nicht, dass uns einfach völlig egal ist, welcher Server welche Daten hat und who cares, sondern irgendwann sollen die schon alle den gleichen Stand haben.

[1:13:18] Das ist schon wichtig, dass das irgendwann mal der Fall ist, aber im Zweifel ist es nicht so wichtig, dass das jetzt sofort der Fall ist. Das kann auch in 5 Minuten sein. Wenn ich Pech habe, auch mal in 5 Stunden, weil da gerade ein Server ausgefallen ist. Das ist alles okay, aber es ist bitte nicht unser Ziel, NIEMALS einen konsistenten Zustand zu haben. Darum geht es nicht, sondern steht immer nur im Vordergrund.

[1:13:38] Genau wie bei ACID die Konsistenz im Vordergrund steht, aber ich natürlich trotzdem will, dass die Datenbank verfügbar ist. Und wenn alles gut läuft, ist sie das ja auch. Aber das Problem ist, wenn es mal nicht gut läuft, dann würde ich halt eher die Konsistenz wählen statt die Verfügbarkeit. Und bei BASE ist es halt umgekehrt. Wenn es da mal nicht läuft, dann würde ich sagen, egal, scheiß auf die Konsistenz, Hauptsache die Daten sind verfügbar und werden ausgeliefert. Stichwort Netflix.

[1:14:03] Gut, und das EVENTUAL bedeutet, Vorsicht, kennst du noch aus dem Englischunterricht, aus der Schule, die FALSE FRIENDS im Deutsch, sage ich immer gerne. EVENTUAL liest sich so schön wie EVENTUELL in Deutsch. EVENTUAL, EVENTUELL ist aber leider nicht das gleiche. Das ist ein FALSE FRIEND. EVENTUAL heißt schlussendlich und nicht eventuell. Also eventuelle Konsistenz könnte ja bedeuten, vielleicht haben wir mal irgendwann Konsistenz, vielleicht auch nicht, ist nicht schlimm.

[1:14:31] Aber genau das heißt es nicht, sondern EVENTUAL bedeutet, es wird irgendwann einmal definitiv Konsistenz geben. Schlussendlich, am Ende wird es Konsistenz geben. Das bedeutet das EVENTUAL CONSISTENCY. Das heißt bis zu diesem Zeitpunkt könnte die Datenbank inkonsistente Rückmeldungen geben, aber irgendwann einmal wird das glatt gezogen und dann ist die Datenbank komplett konsistent. Im Fall von Netflix auch weltweit dann zum Beispiel, haben alle Datenbanken wieder den gleichen Stand.

[1:14:59] So, das ist das BASE. BASICALLY AVAILABLE, SOFT STATE, EVENTUAL CONSISTENCY. Also, Gegenentwurf zu ACID. Damit haben wir heute glaube ich jetzt mal alles abgehakt, was irgendwie mit Transaktionen zu tun hat und jetzt bin ich auch durch. Ich würde sagen, wir machen jetzt mal einen Haken dran.

[1:15:14] Ich hoffe, dass dir die Methode, wollte ich schon sagen hier, die Episode heute ein bisschen was gebracht hat und dir die Datenbank Transaktionen etwas näher gebracht haben. Wenn du noch Fragen hast oder dir irgendwas komisch vorkam, dann schreib mir gerne einen Kommentar unter der Episode. Wie immer findest du die Shownotes, da habe ich übrigens auch die ganzen Beispiele drin und Links zu noch ein paar Wikipedia Artikeln, wo dann noch ein paar Sachen im Detail erklärt werden.

[1:15:36] Vor allem diese Geschichten mit Isolation und so weiter. Wenn du das nicht ganz hundertprozentig verstanden hast, gerne nochmal nachlesen. Ist übrigens, das spoilere ich mal ein bisschen, nicht prüfungsrelevant. Ich glaube nicht, dass das jemals abgefragt wird. Also diese DIRTY-READ-Geschichten und READ-UNCOMMITTED, diese Isolation von Transaktionen.

[1:15:52] Ich finde das wichtig, das zu wissen und gehört zu haben und zu verstehen. Wird, glaube ich, niemals in der Prüfung drankommen. Aber dieses ACID-Zeug, hochgradig prüfungsrelevant, wurde auch schon explizit in der schriftlichen Prüfung abgefragt tatsächlich. Und ich könnte mir vorstellen, dass diese CAP und BASE-Geschichten auch reinkommen. Denn NoSQL-Datenbanken sind heute so verbreitet und eine verteilte Anwendung ist auch nichts Außergewöhnliches mehr. Von daher, das würde ich mir schon nochmal anschauen, auch für eine Prüfung.

[1:16:17] Aber viel wichtiger finde ich das Ganze überhaupt für die Praxis, weil wir wollen ja jetzt hier nicht nur für die Prüfung lernen, sondern auch für unseren IT-Alltag. Und da werden wir das bestimmt, oder du wirst das bestimmt, irgendwo mal wiederfinden.

[1:16:27] So, was wollte ich jetzt eigentlich sagen? Ach ja, Shownotes, genau. Die sind ein bisschen ausführlicher für diese Episode. Guck da gerne nochmal rein unter itberufe-podcast.de slash 187 für die 187. So, die ist heute wahr. Genau, guck da gerne rein.

[1:16:43] Und falls du noch nicht angemeldet bist für meinen Newsletter, den kann ich dir noch wärmstens ans Herz legen. Der begleitet dich durch die drei Jahre der Ausbildung, egal ob du Azubi bist oder Ausbilder oder Ausbilderin. Und du kriegst ungefähr einmal die Woche eine Mail von mir mit dem passenden Inhalt zu deinem Ausbildungsstand. Beispiel erstes Ausbildungsjahr, da geht es um deine Rechte und Pflichten als Azubi und so weiter. Im dritten Ausbildungsjahr geht es dann um die Vorbereitung des Abschlussprojekts und so weiter.

[1:17:06] Meld dich gerne an, alles kostenfrei. Wenn du keine Lust mehr drauf hast, einfach auf Abmelden klicken. In jeder Mail findest du einen Link. Kannst du dir gerne anschauen unter itberufe-podcast.de slash Newsletter. Das würde mich freuen. So, das war es für heute zum Thema Datenbanktransaktionen. Wir hören uns beim nächsten Mal wieder. Mach's gut und bis zum nächsten Mal. Ciao.

[1:17:36] Untertitel im Auftrag des ZDF für funk, 2017

Polyglot Clean Code Developer
About the Author
Ausbildungsleiter für Fachinformatiker:innen Anwendungsentwicklung, IHK-Prüfer und ehemaliger Hochschuldozent für Programmierung und Software-Engineering.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert