Master’s Thesis - Exam.pdf

Master’s Thesis - Exam
Aufgabe 1) Du arbeitest als Softwarearchitekt bei einem großen Unternehmen, das eine bestehende monolithische Anwendung zu einer skalierbaren und wartbaren Microservice-Architektur umgestalten möchte. Grundlegende Anforderungen an das neue System beinhalten die Verbesserung der Wartbarkeit, Erweiterbarkeit und Skalierbarkeit der Software. Dabei sollst Du verschiedene Entwurfsmuster und Architektur...

© StudySmarter 2024, all rights reserved.

Aufgabe 1)

Du arbeitest als Softwarearchitekt bei einem großen Unternehmen, das eine bestehende monolithische Anwendung zu einer skalierbaren und wartbaren Microservice-Architektur umgestalten möchte. Grundlegende Anforderungen an das neue System beinhalten die Verbesserung der Wartbarkeit, Erweiterbarkeit und Skalierbarkeit der Software. Dabei sollst Du verschiedene Entwurfsmuster und Architekturstile berücksichtigen, die wesentlichen Konzepte der Modularität, Abstraktion, Wiederverwendung und lose Kopplung umsetzen und passende Werkzeuge wie UML-Diagramme oder Architekturbeschreibungs-Sprachen (ADLs) nutzen.

a)

Entwickle eine UML-Komponenten-Diagramm für die neue Microservice-Architektur, die den Übergang von der monolithischen Anwendung darstellt. Identifiziere dabei mindestens fünf zentrale Microservices und beschreibe ihre Hauptfunktionen sowie die Schnittstellen, über die sie miteinander kommunizieren.

Lösung:

Um die bestehende monolithische Anwendung zu einer skalierbaren und wartbaren Microservice-Architektur umzuwandeln, benötigen wir ein UML-Komponenten-Diagramm, das die verschiedenen Microservices und ihre Interaktionen beschreibt. Hier sind die Schritte zur Erstellung des Diagramms sowie eine Beschreibung der zentralen Microservices:

  • Benutzerverwaltung-Service: Dieser Microservice ist für die Verwaltung der Benutzerinformationen zuständig. Hauptfunktionen: - Benutzer hinzufügen - Benutzer löschen - Benutzerinformationen aktualisieren - Benutzerinformationen abrufenSchnittstellen: RESTful API
  • Produktkatalog-Service: Der Produktkatalog-Service verwaltet alle Informationen zu den Produkten.Hauptfunktionen: - Produkt hinzufügen - Produkt aktualisieren - Produktinformationen abrufenSchnittstellen: RESTful API
  • Bestellverwaltung-Service: Dieser Microservice ist für die Verwaltung der Bestellungen zuständig.Hauptfunktionen: - Bestellung erstellen - Bestellung aktualisieren - Bestellung abrufenSchnittstellen: RESTful API
  • Zahlungsservice: Der Zahlungsservice bearbeitet alle Zahlungsprozesse.Hauptfunktionen: - Zahlung abwickeln - Rückerstattung bearbeiten - Zahlungsmethoden verwaltenSchnittstellen: RESTful API, externe Zahlungsschnittstellen (z.B. PayPal, Stripe)
  • Benachrichtigungs-Service: Dieser Service versendet Benachrichtigungen an die Nutzer.Hauptfunktionen: - Benachrichtigungen erstellen - Benachrichtigungen versendenSchnittstellen: Messaging-Systeme (z.B. RabbitMQ, Kafka)

Hier ist das UML-Komponenten-Diagramm, das den Übergang darstellt:

UML-Komponenten-Diagramm
UML-Diagramm Struktur:
+---------------------+    +---------------------+| Benutzerverwaltung  |    | Produktkatalog      || Service             |    | Service             |+---------------------+    +---------------------+| + addUser()         |    | + addProduct()       || + deleteUser()      |    | + updateProduct()    || + updateUser()      |    | + getProduct()       || + getUser()         |    +---------------------++---------------------+              |         |                        |         |                        |         |REST API                |REST API         v                        v+---------------------+    +---------------------+| Bestellverwaltung   |    | Zahlungsservice     || Service             |    |                    |+---------------------+    +---------------------+| + createOrder()     |    | + processPayment() || + updateOrder()     |    | + refundPayment()   || + getOrder()        |    | + managePayment()   |+---------------------+    +---------------------+         |                        |         |REST API                |Externe API         v                        v+---------------------+    +---------------------+| Benachrichtigungen  |    | Externer Zahlungs-  || Service             |    | Gateway             |+---------------------+    +---------------------+| + createNotification|   /| + connect()         || + sendNotification()|  / | + disconnect()      |+---------------------+  //+---------------------+ 

b)

Diskutiere den Einsatz von Entwurfsmustern in der neuen Microservice-Architektur. Wähle zwei spezifische Entwurfsmuster aus (zum Beispiel: Factory, Singleton, Adapter, Proxy) und erkläre, wie diese zur Lösung von typischen Herausforderungen in einer Microservice-Architektur (wie lose Kopplung, Wiederverwendbarkeit, und Skalierbarkeit) beitragen können.

Lösung:

In der Entwicklung einer Microservice-Architektur ist der Einsatz von Entwurfsmustern unerlässlich, um typische Herausforderungen wie lose Kopplung, Wiederverwendbarkeit und Skalierbarkeit zu bewältigen. Hier sind zwei spezifische Entwurfsmuster und ihre Anwendungen:

1. Adapter-Muster

Das Adapter-Muster ermöglicht es, die Schnittstellen eines Dienstes so anzupassen, dass sie mit denen eines anderen, möglicherweise inkompatiblen Dienstes übereinstimmen. Dieses Muster ist besonders nützlich in einer Microservice-Architektur, da es hilft, lose Kopplung und Wiederverwendbarkeit zu fördern.

  • Anwendung: In einem Microservice-System könnte ein alter Dienst (oder ein Drittanbieterdienst) existieren, dessen Schnittstelle nicht den aktuellen Anforderungen entspricht. Ein Adapter kann eingeführt werden, um die Schnittstelle des alten Dienstes an die neue Schnittstelle anzupassen.
  • Vorteile:- Erhöht die Wiederverwendbarkeit von Diensten, da ein einzelnes Service-Interface mehrfach verwendet werden kann.- Fördert lose Kopplung, da die jeweiligen Services unabhängig voneinander verändert werden können, ohne das gesamte System zu beeinträchtigen.

2. Proxy-Muster

Das Proxy-Muster stellt eine Stellvertreter-Klasse bereit, die die Funktionalität eines anderen Dienstes kapselt und kontrolliert. Dieses Muster kann in einer Microservice-Architektur verwendet werden, um Skalierbarkeit und Sicherheit zu erhöhen.

  • Anwendung: Angenommen, ein Microservice-System hat einen Dienst, der kostspielige Operationen ausführt (z.B. Datenbankzugriffe oder externe API-Aufrufe). Ein Proxy kann hier eingeführt werden, um solche Zugriffe zu kontrollieren, Caching zu implementieren, oder zusätzliche Sicherheitsschichten hinzuzufügen.
  • Vorteile:- Erhöht die Skalierbarkeit durch Implementierung von Caching-Strategien, die die Last auf die zugrundeliegenden Dienste reduzieren.- Bietet zusätzliche Sicherheit, indem Zugriffe auf kritischen Ressourcen kontrolliert und überwacht werden.

Zusammen fördern das Adapter-Muster und das Proxy-Muster die lose Kopplung, Wiederverwendbarkeit und Skalierbarkeit, indem sie die Dienste voneinander unabhängig halten und eine flexible Integration und Kontrolle ermöglichen.

Aufgabe 2)

Angenommen, Du arbeitest an einem Projekt, bei dem Du eine große Menge an Daten effizient durchsuchen und sortieren musst. Die Daten werden zunächst in einer unsortierten Liste bereitgestellt. Diese Liste enthält n Elemente, wobei n sehr groß sein kann und daher eine effiziente Verarbeitung erforderlich ist. Du entscheidest Dich dafür, eine hybride Struktur bestehend aus einer Kombination von Arrays und Bäumen zu verwenden und benötigst einen Algorithmus, der die Daten zuerst sortiert und dann eine effiziente Suche ermöglicht.

a)

Implementiere in der Programmiersprache Deiner Wahl einen Algorithmus, der die gegebene unsortierte Liste von n Elementen mit Hilfe des MergeSort-Algorithmus sortiert. Erläutere die Komplexität Deines Algorithmus sowohl in Bezug auf die Laufzeit als auch den Speicherbedarf in der Big-O-Notation.

Lösung:

MergeSort-Algorithmus in Python

Um die gegebene unsortierte Liste von n Elementen mit dem MergeSort-Algorithmus zu sortieren, ist die Implementierung wie folgt:

def merge_sort(arr):    if len(arr) > 1:        mid = len(arr) // 2        left_half = arr[:mid]        right_half = arr[mid:]        merge_sort(left_half)        merge_sort(right_half)        i = j = k = 0        while i < len(left_half) and j < len(right_half):            if left_half[i] < right_half[j]:                arr[k] = left_half[i]                i += 1            else:                arr[k] = right_half[j]                j += 1            k += 1        while i < len(left_half):            arr[k] = left_half[i]            i += 1            k += 1        while j < len(right_half):            arr[k] = right_half[j]            j += 1            k += 1    return arr# Beispielnutzung:unsorted_list = [34, 7, 23, 32, 5, 62]sorted_list = merge_sort(unsorted_list)print(sorted_list)

Erklärung des MergeSort-Algorithmus:

  • Der MergeSort-Algorithmus ist ein teilender Algorithmus, der ein bestehendes Array in kleinere Arrays aufteilt.
  • Es teilt das Array rekursiv in zwei Hälften, bis jedes Teilarray nur noch ein Element enthält.
  • Anschließend werden diese Teilarrays Schritt für Schritt miteinander zusammengemischt (merge) und dabei sortiert.

Komplexitätsanalyse:

  • Laufzeitkomplexität: Die Laufzeitkomplexität des MergeSort-Algorithmus beträgt O(n log n). Dieses Ergebnis ergibt sich aus der Tatsache, dass das Array log(n)-mal aufgeteilt wird und das Zusammenmischen der Teilarrays jeweils O(n) Operationen erfordert.
  • Speicherbedarf: Der Speicherbedarf des MergeSort-Algorithmus beträgt O(n), da zusätzliches Speicher für die Teilarrays benötigt wird, die in den Rekursionsaufrufen erstellt werden.

b)

Nach der Sortierung möchtest Du die Daten in einem binären Suchbaum (Binary Search Tree, BST) speichern, um eine effiziente Suche zu ermöglichen. Implementiere in der gleichen Programmiersprache einen Algorithmus, der die sortierte Liste in einen BST umwandelt. Zeige dann, wie eine binäre Suche im Baum durchgeführt wird, und erläutere die Zeitkomplexität dieser Suche im besten, durchschnittlichen und schlimmsten Fall.

Lösung:

Erstellen eines Binary Search Tree (BST) aus einer sortierten Liste und binäre Suche

Um die sortierte Liste in einen Binary Search Tree (BST) umzuwandeln, sowie eine binäre Suche im BST durchzuführen, verwenden wir das folgende Python-Programm:

class TreeNode:    def __init__(self, key):        self.left = None        self.right = None        self.val = keydef sorted_list_to_bst(sorted_list):    if not sorted_list:        return None    mid = len(sorted_list) // 2    root = TreeNode(sorted_list[mid])    root.left = sorted_list_to_bst(sorted_list[:mid])    root.right = sorted_list_to_bst(sorted_list[mid+1:])    return rootdef binary_search_bst(root, value):    if root is None or root.val == value:        return root    if value < root.val:        return binary_search_bst(root.left, value)    else:        return binary_search_bst(root.right, value)# Beispielnutzung:sorted_list = [5, 7, 23, 32, 34, 62]bst_root = sorted_list_to_bst(sorted_list)search_result = binary_search_bst(bst_root, 23)if search_result:    print("Wert gefunden: ", search_result.val)else:    print("Wert nicht gefunden")

Erklärung:

  • Die Funktion sorted_list_to_bst erstellt einen ausgeglichenen BST aus einer sortierten Liste, indem sie rekursiv den Mittelwert der Liste als Wurzel nimmt und die gleiche Vorgehensweise für die linken und rechten Unterlisten verwendet.
  • Die Funktion binary_search_bst sucht rekursiv nach einem Wert im BST, indem sie nach links geht, wenn der Wert kleiner ist, und nach rechts, wenn der Wert größer ist.

Komplexitätsanalyse der binären Suche:

  • Bester Fall: Die Zeitkomplexität im besten Fall beträgt O(1), wenn der gesuchte Schlüssel an der Wurzel gefunden wird.
  • Durchschnittlicher Fall: Die Zeitkomplexität im durchschnittlichen Fall beträgt O(log n), da im Durchschnitt die Suche in einem ausgeglichenen BST durchgeführt wird.
  • Schlimmster Fall: Die Zeitkomplexität im schlimmsten Fall beträgt O(n), wenn der BST entartet ist und wie eine verlinkte Liste aussieht (d.h. alle Elemente sind entweder nur in einem rechten oder linken Kind).

Aufgabe 3)

Stellen Sie sich vor, Sie werden beauftragt, ein maschinelles Lernmodell zu entwickeln, um Kundenrezensionen eines Online-Shops automatisch zu klassifizieren. Ihre Aufgabe ist es, ein geeignetes Machine-Learning-Modell zu implementieren und zu bewerten.

a)

Beschreiben Sie, welcher Typ maschinellen Lernens (supervised, unsupervised oder reinforcement) in diesem Szenario geeignet ist und warum. Bringen Sie mindestens zwei spezifische Algorithmen oder Modelle, die verwendet werden könnten und erläutern Sie deren Vor- und Nachteile.

Lösung:

In diesem Szenario, in dem Kundenrezensionen eines Online-Shops automatisch klassifiziert werden sollen, ist supervised learning (überwachtes Lernen) die geeignete Art des maschinellen Lernens. Der Grund dafür ist, dass wir eine Menge von Kundenrezensionen haben, die bereits mit Labels versehen sind (z.B. positiv, negativ oder neutral). Diese gelabelten Daten können verwendet werden, um ein Modell zu trainieren, das zukünftige Kundenrezensionen automatisch klassifiziert.

Hier sind zwei spezifische Algorithmen oder Modelle, die verwendet werden könnten:

  • Logistic Regression

    Die logistische Regression ist ein einfaches und leicht interpretierbares Modell, das häufig für binäre Klassifikationsprobleme verwendet wird.

    • Vorteile:
      • Einfach zu implementieren und zu interpretieren.
      • Funktioniert gut bei linear trennbaren Daten.
    • Nachteile:
      • Leistungsabfall bei nicht-linear trennbaren Daten.
      • Kann bei großen Datensätzen und mehreren Features langsam sein.
  • Support Vector Machines (SVM)

    Support Vector Machines sind leistungsstarke Klassifikationsmodelle, die verwendet werden können, um lineare und nicht-lineare Trennungen in den Daten zu finden.

    • Vorteile:
      • Effektiv in hochdimensionalen Räumen.
      • Funktioniert gut bei nicht-linear trennbaren Daten durch Verwendung von Kernel-Tricks.
    • Nachteile:
      • Kann bei sehr großen Datensätzen speicherintensiv sein.
      • Die Wahl des richtigen Kernels und der Hyperparameter kann kompliziert sein.

b)

Angenommen, Sie entscheiden sich für ein tiefes neuronales Netz, um die Kundenrezensionen zu klassifizieren.

  • Schreiben Sie den Aufbau eines beispielhaften neuronalen Netzes einschließlich der verwendeten Schichten und deren Funktionen (z.B. Convolutional Layer, ReLU, Dropout).
  • Erklären Sie die Rolle der Verlustfunktion und wählen Sie eine geeignete Verlustfunktion für dieses Klassifikationsproblem. Begründen Sie Ihre Wahl.
  • Definieren Sie das Optimierungsverfahren, das Sie verwenden möchten, und erläutern Sie dessen Funktionsweise.

Lösung:

Wenn Du Dich für ein tiefes neuronales Netz entscheidest, um die Kundenrezensionen zu klassifizieren, könntest Du ein Netzwerk wie folgt aufbauen:

  • Ein beispielhafter Aufbau eines neuronalen Netzes:
    • Eingabeschicht (Input Layer):

      Die Daten werden in das neuronale Netz eingespeist. Hier könnten die Kundentexte in Vektorform vorliegen, z.B. als TF-IDF-Vektoren oder durch Wort-Einbettungen (Word Embeddings) wie Word2Vec oder GloVe.

    • Einbettungsschicht (Embedding Layer):

      Falls nicht vorbearbeitet, kann eine Einbettungsschicht die Wörter in Vektorrepräsentationen umwandeln, die für das neuronale Netz verständlich sind.

    • Konvolutionale Schicht (Convolutional Layer):

      Diese Schicht extrahiert lokale Merkmale (Features) aus den Eingabedaten. Convolutional Layers sind vor allem in der Verarbeitung natürlicher Sprache nützlich, um lokalisierte Patterns zu erkennen.

    • ReLU-Aktivierungsfunktion (ReLU Activation Function):

      Die Rectified Linear Unit (ReLU) führt eine nichtlineare Transformation durch, die es dem Netzwerk ermöglicht, komplexere Muster zu lernen.

    • Max-Pooling-Schicht (Max-Pooling Layer):

      Max-Pooling reduziert die räumliche Größe der Repräsentation und senkt die Anzahl der Parameter, was zu einer Reduktion der Rechenressourcen führt. Es extrahiert die wichtigsten Merkmale, indem es den maximalen Wert innerhalb eines bestimmten Fensters nimmt.

    • Dense-Schicht (Fully Connected Layer):

      Diese Schicht verknüpft jedes Neuron der vorherigen Schicht mit jedem Neuron der aktuellen Schicht und aggregiert die extrahierten Merkmale, um zur endgültigen Klassifikation beizutragen.

    • Dropout-Schicht (Dropout Layer):

      Dropout verhindert Überanpassung (Overfitting), indem zufällig ein Teil der Neuronen während des Trainings weggelassen wird.

    • Ausgabeschicht (Output Layer):

      Die finale Schicht, die die Klassifikation der Kundenrezensionen vornimmt. Für ein Mehrklassen-Klassifikationsproblem könnte dies eine Softmax-Schicht sein, die Wahrscheinlichkeiten für jede Klasse ausgibt.

  • Rolle der Verlustfunktion und Wahl:

    Die Verlustfunktion misst, wie gut oder schlecht das neuronale Netz bei einer gegebenen Aufgabe abschneidet. Sie berechnet den Unterschied zwischen den vorhergesagten und den tatsächlichen Werten und gibt dem Modell eine Richtung zur Verbesserung. Für dieses Klassifikationsproblem wäre cross-entropy loss geeignet, da es bei Mehrklassen-Klassifikationen gut funktioniert. Die Kreuzentropie-Verlustfunktion quantifiziert die Differenz zwischen den wahrscheinlichen Verteilungen des vorhergesagten Outputs und der tatsächlichen Klasse.

  • Optimierungsverfahren:

    Ein gängiges Optimierungsverfahren ist der Adam-Optimizer. Adam, abgekürzt für Adaptive Moment Estimation, kombiniert die Vorteile von zwei anderen Erweiterungen der stochastischen Gradientenabstiegsalgorithmen, nämlich AdaGrad und RMSProp. Adam ist effizient in Bezug auf Speicher und rechenzeiteffizient.

    • Der Optimierungsprozess umfasst:
      • Berechnung der Gradienten des Verlusts in Bezug auf die Modellparameter.
      • Verwendung von Moment-Schätzungen (Mittelwert und Varianz der Gradienten) zur Anpassung der Lernrate für jeden Parameter.
      • Anpassung der Modellparameter in die Richtung, die durch die Gradienten und die momentberechneten Werte zeigt.

Aufgabe 4)

Du arbeitest als Entwickler in einem Unternehmen, das eine große Datenbank mit transaktionalen Anforderungen betreibt. In diesem Zusammenhang ist es Deine Aufgabe, sicherzustellen, dass die Datenbank den ACID-Prinzipien folgt, um Datenintegrität und -konsistenz zu gewährleisten.

a)

Definiere die ACID-Prinzipien und erkläre, warum jedes dieser Prinzipien entscheidend für Datenbanktransaktionen ist. Verwende dabei konkrete Beispiele.

Lösung:

Die ACID-Prinzipien sind entscheidend für die Gewährleistung von Datenintegrität und -konsistenz in Datenbanktransaktionen. Sie bestehen aus den folgenden vier Prinzipien:

  • Atomicity (Atomarität): Dieses Prinzip bedeutet, dass jede Transaktion als unteilbare Einheit betrachtet wird, die entweder vollständig abgeschlossen oder vollständig rückgängig gemacht wird. Beispielsweise, wenn ein Geldbetrag von Konto A zu Konto B überwiesen wird, muss die gesamte Transaktion entweder vollständig erfolgreich sein (der Betrag wird von Konto A abgebucht und zu Konto B gutgeschrieben) oder gar nicht stattfinden (keine Änderung an beiden Kontos).
  • Consistency (Konsistenz): Konsistenz bedeutet, dass eine Transaktion einen konsistenten Zustand in der Datenbank hinterlässt. Beispielsweise, wenn die Geschäftslogik vorschreibt, dass der Kontostand niemals negativ sein darf, dann darf nach einer Transaktion dieser Zustand nicht verletzt werden. Eine fehlgeschlagene Transaktion muss daher alle Änderungen zurücksetzen, um die Konsistenz wiederherzustellen.
  • Isolation (Isolation): Dieses Prinzip garantiert, dass Transaktionen so ausgeführt werden, als wären sie isoliert voneinander. Das bedeutet, dass parallele Transaktionen keinen gegenseitigen Einfluss auf ihre Zwischenergebnisse haben. Beispiel: Wenn zwei Transaktionen gleichzeitig Tickets für denselben Flug buchen, sollte jede Transaktion isoliert arbeiten, sodass am Ende keine doppelten Buchungen erfolgen.
  • Durability (Dauerhaftigkeit): Durability garantiert, dass das Ergebnis einer abgeschlossenen Transaktion auch bei Systemausfällen dauerhaft gespeichert bleibt. Beispiel: Wenn eine Bestellung abgeschickt wird und das System danach abstürzt, müssen die Informationen zur Bestellung auch nach dem Neustart des Systems noch vorhanden sein.

Jedes dieser Prinzipien spielt eine entscheidende Rolle bei der Sicherstellung der Zuverlässigkeit und Stabilität von Datenbanktransaktionen:

  • Atomicity: Verhindert inkonsistente Teilzustände.
  • Consistency: Gewährleistet Einhaltung der Geschäftsregeln und Datenintegrität.
  • Isolation: Verhindert unerwartete Wechselwirkungen zwischen parallelen Transaktionen.
  • Durability: Schützt Daten vor Verlust bei Systemfehlern oder Abstürzen.

b)

Angenommen, Du hast eine Datenbank mit zwei Tabellen: Konten und Überweisungen. Zeige, wie eine Überweisung von 100€ von Konto A zu Konto B implementiert werden kann, indem Du die Konzepte von Rollback und Commit verwenden, um die Atomarität zu gewährleisten. Unterstreiche auch, wie die Isolation durch entsprechende Sperrmechanismen erzielt werden kann. Verwende SQL-Codefragmente zur Veranschaulichung.

Lösung:

Um eine Überweisung von 100€ von Konto A zu Konto B zu implementieren und dabei die ACID-Prinzipien zu gewährleisten, kannst Du folgendes Vorgehen nutzen. Hierbei spielen vor allem die Konzepte von Rollback, Commit und Sperrmechanismen eine wichtige Rolle.

SQL-Codefragmente zur Veranschaulichung

Der folgende SQL-Code zeigt, wie die Überweisung von 100€ von Konto A zu Konto B unter Einbeziehung von Atomarität (durch Verwendung von Commit und Rollback) und Isolation (durch Sperrmechanismen) durchgeführt werden kann:

-- Beginn der TransaktionBEGIN TRANSACTION;-- Sperre beide Konten, um Isolation zu gewährleisten-- Verhindert, dass andere Transaktionen auf diese Daten zugreifenLOCK TABLE Konten IN EXCLUSIVE MODE;-- Abheben vom Konto AUPDATE KontenSET saldo = saldo - 100WHERE konto_id = 'A';-- Falls der Saldo von Konto A nach dem Abheben negativ wird, Rolle die Transaktion zurückIF (SELECT saldo FROM Konten WHERE konto_id = 'A') < 0 THEN    ROLLBACK TRANSACTION;    THROW 'Fehler: Nicht ausreichender Saldo';END IF;-- Gutschreiben auf Konto BUPDATE KontenSET saldo = saldo + 100WHERE konto_id = 'B';-- Protokolliere die Überweisung in der Tabelle ÜberweisungenINSERT INTO Überweisungen (konto_von, konto_zu, betrag, transf_datum)VALUES ('A', 'B', 100, CURRENT_TIMESTAMP);-- Wenn alle Schritte erfolgreich abgeschlossen sind, committe die TransaktionCOMMIT TRANSACTION;-- FehlerbehandlungsmechanismusEXCEPTION    WHEN OTHERS THEN        -- Im Fehlerfall rolle die gesamte Transaktion zurück        ROLLBACK TRANSACTION;        THROW 'Transaktion fehlgeschlagen';END;

Erklärung der Konzepte

  • Atomarität: Die Transaktion wird als unteilbare Einheit behandelt. Jeder Schritt (Abheben vom Konto A, Gutschreiben auf Konto B) wird nur dann ausgeführt, wenn alle Bedingungen erfüllt sind. Falls ein Fehler auftritt oder eine Bedingung nicht erfüllt ist (z. B. wenn Konto A nicht genügend Saldo hat), wird die gesamte Transaktion mit ROLLBACK rückgängig gemacht, um Teilzustände zu vermeiden.
  • Commit: Wenn alle Schritte der Transaktion erfolgreich sind, wird die Transaktion mit COMMIT abgeschlossen, wodurch alle Änderungen dauerhaft gespeichert werden.
  • Isolation: Durch Sperrmechanismen wie LOCK TABLE wird sichergestellt, dass andere Transaktionen keinen Zugriff auf die betroffenen Daten haben, solange die aktuelle Transaktion nicht abgeschlossen ist. Das verhindert Konflikte und unerwartete Wechselwirkungen.

Durch diese Vorgehensweise werden die ACID-Prinzipien in der Datenbanktransaktion gewährleistet, um Datenintegrität und -konsistenz sicherzustellen.

c)

Erkläre das Zwei-Phasen-Sperrprotokoll (2PL) und diskutiere, wie es hilft, die Serialisierbarkeit zu gewährleisten. Verwende ein Szenario mit zwei konkurrierenden Transaktionen als Beispiel und illustriere, wie das Protokoll dazu beiträgt, Konflikte zu vermeiden.

Lösung:

Das Zwei-Phasen-Sperrprotokoll (2PL) ist ein Sperrmechanismus in Datenbanksystemen, der hilft, die Serialisierbarkeit von Transaktionen zu gewährleisten. Das Protokoll besteht aus zwei Phasen: der wachsenden Phase und der schrumpfenden Phase.

Phasen des 2PL

  • Wachsende Phase: In dieser Phase können Transaktionen Sperren anfordern und erhalten, jedoch keine Sperren freigeben.
  • Shrinking Phase (Schrumpfende Phase): In dieser Phase können Transaktionen Sperren freigeben, jedoch dürfen keine neuen Sperren mehr angefordert werden.

Dieses Protokoll stellt sicher, dass im Verlauf der Transaktion keine Sperren mehr hinzugefügt werden, sobald eine Sperre freigegeben wird, wodurch zyklische Abhängigkeiten und Konflikte vermieden werden.

Beispiel-Szenario mit zwei Transaktionen

Betrachten wir zwei konkurrierende Transaktionen T1 und T2 in einer Datenbank mit zwei Konten A und B:

-- Transaktion T1: Überweisung von Konto A auf Konto BBEGIN;LOCK TABLE Konten IN EXCLUSIVE MODE;UPDATE Konten SET saldo = saldo - 100 WHERE konto_id = 'A';UPDATE Konten SET saldo = saldo + 100 WHERE konto_id = 'B';COMMIT;
-- Transaktion T2: Überprüfung des Saldos von Konto A und Konto BBEGIN;LOCK TABLE Konten IN SHARE MODE;SELECT saldo FROM Konten WHERE konto_id = 'A';SELECT saldo FROM Konten WHERE konto_id = 'B';COMMIT;

In diesem Szenario passiert Folgendes:

  1. T1 beginnt und sperrt die Tabelle Konten im exklusiven Modus (Exclusive Lock), um Änderungen an Konten vorzunehmen.
  2. Da T1 eine exklusive Sperre hält, kann T2 keine Lese-Sperre (Shared Lock) erhalten und muss warten, bis T1 abgeschlossen ist.
  3. T1 führt alle notwendigen Updates durch und commit-t die Transaktion, wodurch die Sperren freigegeben werden.
  4. Jetzt kann T2 die Tabelle Konten im Shared Mode sperren und die Saldos überprüfen.

Durch dieses Sperrprotokoll wird sichergestellt, dass T2 erst dann Zugriff erhält, wenn T1 vollständig abgeschlossen ist, wodurch Konflikte und inkonsistente Zustände verhindert werden. Die Serialisierbarkeit wird somit gewährleistet, da die Transaktionen so ausgeführt werden, als wären sie seriell gereiht (d.h. nacheinander) erfolgt.

Zusammenfassung

Das Zwei-Phasen-Sperrprotokoll hilft, die Serialisierbarkeit zu gewährleisten, indem es sicherstellt, dass Sperranforderungen und -freigaben in definierten Phasen erfolgen. Dadurch werden zyklische Abhängigkeiten und Konflikte zwischen konkurrierenden Transaktionen vermieden, wodurch konsistente und isolierte Transaktionsausführungen gewährleistet werden.

Sign Up

Melde dich kostenlos an, um Zugriff auf das vollständige Dokument zu erhalten

Mit unserer kostenlosen Lernplattform erhältst du Zugang zu Millionen von Dokumenten, Karteikarten und Unterlagen.

Kostenloses Konto erstellen

Du hast bereits ein Konto? Anmelden