diff --git a/.idea/cds-104 Datenbanken und Datenverarbeitung.iml b/.idea/cds-104 Datenbanken und Datenverarbeitung.iml
index c69f1c9..d8b3f6c 100644
--- a/.idea/cds-104 Datenbanken und Datenverarbeitung.iml
+++ b/.idea/cds-104 Datenbanken und Datenverarbeitung.iml
@@ -2,7 +2,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/data_source_mapping.xml b/.idea/data_source_mapping.xml
deleted file mode 100644
index c8be428..0000000
--- a/.idea/data_source_mapping.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5f4a9fa..977706b 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml
index 0254c70..6df4889 100644
--- a/.idea/sqldialects.xml
+++ b/.idea/sqldialects.xml
@@ -1,10 +1,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Block-1/Aufgabe_3:_Recherche_zu_SQL_Features.pdf b/Block-1/Aufgabe_3:_Recherche_zu_SQL_Features.pdf
deleted file mode 100644
index 2c102e7..0000000
Binary files a/Block-1/Aufgabe_3:_Recherche_zu_SQL_Features.pdf and /dev/null differ
diff --git a/Block-2/seminarplatz_vergabe.ipynb b/Block-2/seminarplatz_vergabe.ipynb
new file mode 100644
index 0000000..205510c
--- /dev/null
+++ b/Block-2/seminarplatz_vergabe.ipynb
@@ -0,0 +1,417 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Seminarplatz-Vergabe\n",
+ "\n",
+ "In folgendem Problem geht es darum, dass eine Gruppe von Studierenden einen oder mehrere Seminarplätze in einem Kurs bekommen sollen. Es gibt 8 Seminargruppen mit insgesamt 40 Plätzen, diese sind in der Tabelle `seminar_sessions` abgelegt.\n",
+ "\n",
+ "Bei einer Anmeldung einer einzelnen Person wird die Anzahl der Plätze in der Tabelle `seminar_sessions` um 1 reduziert und ein Eintrag in der Tabelle `seminar_registrations` erstellt. Dies darf natürlich nur passieren, wenn noch Plätze verfügbar sind.\n",
+ "\n",
+ "Die Anzahl der vergebenen Plätze in der Tabelle `seminar_registrations` und die Anzahl der verfügbaren Plätze in der Tabelle `seminar_sessions` müssen konsistent sein, also in der Summe 40 ergeben.\n",
+ "\n",
+ "In einem Lasttest mit mehreren Threads zeigt sich: Die Anzahl der vergebenen Plätze in der Tabelle `seminar_registrations` und die Anzahl der verfügbaren Plätze in der Tabelle `seminar_sessions` sind nicht konsistent! \n",
+ "\n",
+ "### Ihre Aufgabe:\n",
+ "Führen Sie geeignete Transaktionen ein, um die Konsistenz zu gewährleisten!\n",
+ "\n",
+ "Implementierungen Sie dazu zunächst die Funktionen, die mit TODO gekennzeichnet sind, und passen Sie die Funktion `reserve_seat` an, um die Konsistenz zu gewährleisten.\n",
+ "\n",
+ "Am Code des Lasttests müssen Sie nichts ändern, er dient nur dazu, das Problem zu demonstrieren.\n",
+ "\n",
+ "### Bemerkungen:\n",
+ "\n",
+ "- nicht jeder Durchlauf verursacht Inkonsistenzen, manchmal müssen Sie den Code mehrmals ausführen, um Inkonsistenzen zu finden\n",
+ "- auch Deadlocks können auftreten, diese müssen auch vermieden werden\n",
+ "- die User-Tabelle wurde weggelassen, da sie für das Problem nicht relevant ist\n",
+ "- an manchen Stellen ist der Code absichtlich etwas ineffizient gehalten, um die Inkonsistenzen zu begünstigen (z.B. würden Probleme mit Inkonsistenzen seltener auftreten, wenn die Query `UPDATE seminar_sessions SET seats = seats-1` lauten würde).\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2026-04-19T20:28:20.768652Z",
+ "start_time": "2026-04-19T20:28:20.766464Z"
+ }
+ },
+ "source": [
+ "import psycopg2\n",
+ "import psycopg2.extras"
+ ],
+ "outputs": [],
+ "execution_count": 26
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2026-04-19T20:28:21.151712Z",
+ "start_time": "2026-04-19T20:28:21.149462Z"
+ }
+ },
+ "source": [
+ "# Datenbankverbindung herstellen\n",
+ "def get_connection():\n",
+ " conn = psycopg2.connect(\"dbname=seminar user=postgres password=sml12345\")\n",
+ " return conn"
+ ],
+ "outputs": [],
+ "execution_count": 27
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2026-04-19T20:28:37.424939Z",
+ "start_time": "2026-04-19T20:28:37.390822Z"
+ }
+ },
+ "source": [
+ "# Tabelle erzeugen - immer wenn diese Zelle ausgeführt wird, wird die Tabelle neu erzeugt\n",
+ "conn = get_connection()\n",
+ "cursor = conn.cursor()\n",
+ "cursor.execute(\"\"\"\n",
+ " DROP TABLE IF EXISTS seminar_registrations CASCADE;\n",
+ " DROP TABLE IF EXISTS seminar_sessions;\n",
+ " \n",
+ " CREATE TABLE IF NOT EXISTS seminar_sessions (\n",
+ " id SERIAL PRIMARY KEY, \n",
+ " seats INTEGER NOT NULL\n",
+ " );\n",
+ " \n",
+ " INSERT INTO seminar_sessions (seats) VALUES \n",
+ " (4), (4), (5), (5), (4), (10), (5), (3);\n",
+ " \n",
+ " \n",
+ " CREATE TABLE IF NOT EXISTS seminar_registrations (\n",
+ " user_id INTEGER NOT NULL,\n",
+ " session_id INTEGER NOT NULL,\n",
+ " FOREIGN KEY (session_id) REFERENCES seminar_sessions(id)\n",
+ " ); \n",
+ "\"\"\")\n",
+ "conn.commit()"
+ ],
+ "outputs": [],
+ "execution_count": 33
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2026-04-19T20:28:22.178605Z",
+ "start_time": "2026-04-19T20:28:22.174509Z"
+ }
+ },
+ "source": [
+ "# Hilfsfunktion: Alle Seminar-Sessions ausgeben\n",
+ "def show_sessions():\n",
+ " cursor.execute(\"SELECT * FROM seminar_sessions\")\n",
+ " rows = cursor.fetchall()\n",
+ " print(\"Seminar Sessions:\")\n",
+ " for row in rows:\n",
+ " print(row[0], row[1])\n",
+ "\n",
+ "\n",
+ "# Anzahl aller freien Plätze bestimmen\n",
+ "def count_free_seats():\n",
+ " cursor.execute(\"SELECT sum(seats) FROM seminar_sessions\")\n",
+ " return cursor.fetchone()[0]\n",
+ "\n",
+ "# Anzahl der belegten Plätze bestimmen\n",
+ "def count_occupied_seats():\n",
+ " cursor.execute(\"SELECT count(*) FROM seminar_registrations\")\n",
+ " return cursor.fetchone()[0]\n",
+ "\n",
+ "# Testaufrufe\n",
+ "\n",
+ "show_sessions()\n",
+ "print(\"freie Plätze\", count_free_seats())\n",
+ "print(\"belegte Plätze\", count_occupied_seats())"
+ ],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Seminar Sessions:\n",
+ "1 4\n",
+ "2 4\n",
+ "3 5\n",
+ "4 5\n",
+ "5 4\n",
+ "6 10\n",
+ "7 5\n",
+ "8 3\n",
+ "freie Plätze 40\n",
+ "belegte Plätze 0\n"
+ ]
+ }
+ ],
+ "execution_count": 29
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2026-04-19T20:28:22.832360Z",
+ "start_time": "2026-04-19T20:28:22.829458Z"
+ }
+ },
+ "source": [
+ "# Diese Funktion soll einen Platz reservieren und True zurückgeben, wenn es geklappt hat.\n",
+ "# Wenn kein Platz mehr frei ist, soll False zurückgegeben werden.\n",
+ "def reserve_seat(conn, user_id, session_id):\n",
+ " with conn.cursor() as cursor:\n",
+ " cursor.execute(\"SELECT seats FROM seminar_sessions WHERE id = %s FOR UPDATE\", (session_id,))\n",
+ " seats = cursor.fetchone()[0]\n",
+ "\n",
+ " if seats > 0:\n",
+ " cursor.execute(\"UPDATE seminar_sessions SET seats = %s WHERE id = %s\", (seats-1, session_id,))\n",
+ " cursor.execute(\"INSERT INTO seminar_registrations (user_id, session_id) VALUES (%s, %s)\", (user_id, session_id))\n",
+ " conn.commit()\n",
+ " return True\n",
+ " else:\n",
+ " conn.rollback()\n",
+ " return False\n",
+ " \n"
+ ],
+ "outputs": [],
+ "execution_count": 30
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2026-04-19T20:28:23.903374Z",
+ "start_time": "2026-04-19T20:28:23.900910Z"
+ }
+ },
+ "source": [
+ "import random \n",
+ "\n",
+ "# 20 zufällige Anmeldungen durchführen - diese Funktion wird später als Thread gestartet\n",
+ "def random_seat_reservation(n=20):\n",
+ " # jeder Thread hat seine eigene Verbindung\n",
+ " conn = get_connection()\n",
+ " \n",
+ " # n mal einen zufälligen Platz für eine zufällige User-ID reservieren\n",
+ " for _ in range(n):\n",
+ " random_user_id = random.randint(1, 100)\n",
+ " random_session_id = random.randint(1, 8)\n",
+ "\n",
+ " if reserve_seat(conn, random_user_id, random_session_id):\n",
+ " print(\"User\", random_user_id, \"hat sich für Session\", random_session_id, \"angemeldet\")\n",
+ " else:\n",
+ " print(\"Session\", random_session_id, \"ist ausgebucht\")"
+ ],
+ "outputs": [],
+ "execution_count": 31
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2026-04-19T20:28:40.301148Z",
+ "start_time": "2026-04-19T20:28:40.248650Z"
+ }
+ },
+ "source": [
+ "import threading\n",
+ "\n",
+ "# Diese Funktion gibt Informationen über die Belegung der Seminare aus\n",
+ "def print_info():\n",
+ " print('-'*20)\n",
+ " \n",
+ " free_seats = count_free_seats()\n",
+ " occupied_seats = count_occupied_seats()\n",
+ "\n",
+ " print(\"Freie Plätze:\", free_seats)\n",
+ " print(\"Belegte Plätze:\", occupied_seats)\n",
+ " print(\"Gesamt:\", free_seats + occupied_seats)\n",
+ " \n",
+ " if free_seats + occupied_seats == 40:\n",
+ " print(\"Platzanzahl ist konsistent!\")\n",
+ " else:\n",
+ " print(\"Platzanzahl ist inkonsistent!\")\n",
+ "\n",
+ " print('-'*20)\n",
+ "\n",
+ "# -------------------------------------------------------------------------\n",
+ "# Mini-Lasttest, 5 Threads starten, die jeweils 20 Reservierungen vornehmen\n",
+ "# -------------------------------------------------------------------------\n",
+ "\n",
+ "print(\"Vor dem Lasttest:\")\n",
+ "print_info()\n",
+ "\n",
+ "threads = [ threading.Thread(target=random_seat_reservation) for _ in range(5)]\n",
+ "\n",
+ "# Threads starten\n",
+ "for t in threads:\n",
+ " t.start()\n",
+ "\n",
+ "# Auf das Ende der Threads warten\n",
+ "for t in threads:\n",
+ " t.join()\n",
+ "\n",
+ " \n",
+ "print(\"Nach dem Lasttest:\")\n",
+ "print_info()"
+ ],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Vor dem Lasttest:\n",
+ "--------------------\n",
+ "Freie Plätze: 40\n",
+ "Belegte Plätze: 0\n",
+ "Gesamt: 40\n",
+ "Platzanzahl ist konsistent!\n",
+ "--------------------\n",
+ "User 50 hat sich für Session 2 angemeldet\n",
+ "User 42 hat sich für Session 5 angemeldet\n",
+ "User 59 hat sich für Session 5 angemeldet\n",
+ "User 33 hat sich für Session 8 angemeldet\n",
+ "User 6 hat sich für Session 2 angemeldet\n",
+ "User 30 hat sich für Session 3 angemeldet\n",
+ "User 14 hat sich für Session 5 angemeldet\n",
+ "User 75 hat sich für Session 1 angemeldet\n",
+ "User 44 hat sich für Session 8 angemeldet\n",
+ "User 42 hat sich für Session 5 angemeldet\n",
+ "User 87 hat sich für Session 7 angemeldet\n",
+ "User 44 hat sich für Session 4 angemeldet\n",
+ "User 87 hat sich für Session 2 angemeldet\n",
+ "User 64 hat sich für Session 2 angemeldet\n",
+ "User 83 hat sich für Session 1 angemeldet\n",
+ "User 54 hat sich für Session 1 angemeldet\n",
+ "User 47 hat sich für Session 3 angemeldet\n",
+ "User 23 hat sich für Session 1 angemeldet\n",
+ "Session 2 ist ausgebucht\n",
+ "User 91 hat sich für Session 4 angemeldet\n",
+ "User 22 hat sich für Session 3 angemeldet\n",
+ "Session 2 ist ausgebucht\n",
+ "Session 2 ist ausgebucht\n",
+ "User 86 hat sich für Session 3 angemeldet\n",
+ "User 36 hat sich für Session 4 angemeldet\n",
+ "Session 2 ist ausgebucht\n",
+ "Session 5 ist ausgebucht\n",
+ "User 1 hat sich für Session 8 angemeldet\n",
+ "Session 1 ist ausgebucht\n",
+ "User 3 hat sich für Session 4 angemeldet\n",
+ "User 85 hat sich für Session 7 angemeldet\n",
+ "Session 2 ist ausgebucht\n",
+ "User 32 hat sich für Session 6 angemeldet\n",
+ "Session 5 ist ausgebucht\n",
+ "Session 2 ist ausgebucht\n",
+ "User 29 hat sich für Session 3 angemeldet\n",
+ "User 58 hat sich für Session 6 angemeldet\n",
+ "User 75 hat sich für Session 7 angemeldet\n",
+ "User 50 hat sich für Session 4 angemeldet\n",
+ "Session 2 ist ausgebucht\n",
+ "Session 5 ist ausgebucht\n",
+ "Session 4 ist ausgebucht\n",
+ "User 99 hat sich für Session 6 angemeldet\n",
+ "User 82 hat sich für Session 7 angemeldet\n",
+ "Session 3 ist ausgebucht\n",
+ "Session 2 ist ausgebucht\n",
+ "Session 5 ist ausgebucht\n",
+ "Session 2 ist ausgebucht\n",
+ "Session 2 ist ausgebucht\n",
+ "Session 8 ist ausgebucht\n",
+ "Session 5 ist ausgebucht\n",
+ "Session 2 ist ausgebucht\n",
+ "Session 5 ist ausgebucht\n",
+ "Session 2 ist ausgebucht\n",
+ "Session 3 ist ausgebucht\n",
+ "Session 1 ist ausgebucht\n",
+ "Session 1 ist ausgebucht\n",
+ "User 67 hat sich für Session 6 angemeldet\n",
+ "Session 5 ist ausgebucht\n",
+ "Session 5 ist ausgebucht\n",
+ "User 53 hat sich für Session 7 angemeldet\n",
+ "Session 3 ist ausgebucht\n",
+ "Session 7 ist ausgebucht\n",
+ "Session 8 ist ausgebucht\n",
+ "Session 8 ist ausgebucht\n",
+ "Session 8 ist ausgebucht\n",
+ "Session 7 ist ausgebucht\n",
+ "Session 1 ist ausgebucht\n",
+ "Session 2 ist ausgebucht\n",
+ "Session 4 ist ausgebucht\n",
+ "Session 8 ist ausgebucht\n",
+ "Session 3 ist ausgebucht\n",
+ "Session 3 ist ausgebucht\n",
+ "Session 2 ist ausgebucht\n",
+ "Session 7 ist ausgebucht\n",
+ "Session 4 ist ausgebucht\n",
+ "User 12 hat sich für Session 6 angemeldet\n",
+ "Session 4 ist ausgebucht\n",
+ "Session 4 ist ausgebucht\n",
+ "Session 3 ist ausgebucht\n",
+ "User 68 hat sich für Session 6 angemeldet\n",
+ "Session 5 ist ausgebucht\n",
+ "Session 8 ist ausgebucht\n",
+ "Session 7 ist ausgebucht\n",
+ "Session 2 ist ausgebucht\n",
+ "User 18 hat sich für Session 6 angemeldet\n",
+ "Session 3 ist ausgebucht\n",
+ "Session 4 ist ausgebucht\n",
+ "User 56 hat sich für Session 6 angemeldet\n",
+ "Session 1 ist ausgebucht\n",
+ "Session 7 ist ausgebucht\n",
+ "Session 4 ist ausgebucht\n",
+ "Session 8 ist ausgebucht\n",
+ "Session 1 ist ausgebucht\n",
+ "User 88 hat sich für Session 6 angemeldet\n",
+ "Session 7 ist ausgebucht\n",
+ "Session 5 ist ausgebucht\n",
+ "Session 5 ist ausgebucht\n",
+ "Session 2 ist ausgebucht\n",
+ "User 28 hat sich für Session 6 angemeldet\n",
+ "Nach dem Lasttest:\n",
+ "--------------------\n",
+ "Freie Plätze: 0\n",
+ "Belegte Plätze: 40\n",
+ "Gesamt: 40\n",
+ "Platzanzahl ist konsistent!\n",
+ "--------------------\n"
+ ]
+ }
+ ],
+ "execution_count": 34
+ },
+ {
+ "metadata": {},
+ "cell_type": "code",
+ "outputs": [],
+ "execution_count": null,
+ "source": ""
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "base",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}