Zum Inhalt springen

8. Datenbank-Schnittstellen

Zu Zen-Modus wechseln

Moderne Anwendungen sprechen mit einer Datenbank selten über rohes SQL, das man im Terminal eintippt. Stattdessen nutzen sie standardisierte Datenbank-Schnittstellen — Bibliotheken und Treiber, mit denen Programme in Python, JavaScript, Java, PHP und vielen anderen Sprachen strukturiert, sicher und portabel mit einem RDBMS kommunizieren.

Dieses Kapitel behandelt die wichtigsten Schnittstellenkonzepte und zeigt konkrete Beispiele, wie man aus verbreiteten Programmiersprachen eine Verbindung zu PostgreSQL und MariaDB / MySQL aufbaut und abfragt.

Ohne Standards bräuchte jeder Datenbankhersteller eine eigene proprietäre API. Eine Python-Anwendung, die mit PostgreSQL spricht, sähe völlig anders aus als eine, die mit MariaDB / MySQL oder Oracle spricht. Standards lösen das:

  • ODBC (Open Database Connectivity) — ein API-Standard auf C-Ebene, breit über Sprachen und Plattformen unterstützt. Bietet eine gemeinsame Schnittstelle, sodass eine Anwendung mit minimalen Codeänderungen zwischen verschiedenen Datenbank-Backends wechseln kann.
  • JDBC (Java Database Connectivity) — das Java-Pendant zu ODBC. Jedes größere RDBMS liefert einen JDBC-Treiber.
  • Native Treiber — sprachspezifische Bibliotheken, die direkt mit einem bestimmten DBMS kommunizieren (etwa psycopg2 für Python + PostgreSQL, pg für Node.js + PostgreSQL). Oft schneller und funktionsreicher als generische ODBC-/JDBC-Wrapper.
  • ORMs (Object-Relational Mapper) — höhere Abstraktionen, die Datenbankzeilen auf Objekte der Programmiersprache abbilden (etwa SQLAlchemy für Python, Prisma für Node.js). Nützlich für schnelle Entwicklung, können aber wichtiges SQL-Verhalten verstecken.

Unabhängig von Sprache oder Treiber ist der grundsätzliche Ablauf immer gleich:

  1. Treiber laden — die Anwendung lädt die Treiberbibliothek.
  2. Verbindung aufbauen — der Treiber verbindet sich über einen Connection String (Host, Port, Datenbankname, Benutzername, Passwort) mit dem DBMS.
  3. Cursor / Session öffnen — ein logischer Handle, um Abfragen zu senden und Ergebnisse zu empfangen.
  4. Abfragen ausführen — SQL-Anweisungen werden an die Datenbank gesendet.
  5. Ergebnisse verarbeiten — die Ergebniszeilen werden abgeholt und in der Anwendung genutzt.
  6. Verbindung schließen — die Verbindung wird an einen Pool zurückgegeben oder geschlossen.
Anwendung
Treiber / Connector (z. B. psycopg2, pg, JDBC-Treiber)
Netzwerk (TCP/IP, Unix-Socket)
PostgreSQL-Server (Port 5432)
Database / Schema / Tables

Die meisten Treiber akzeptieren einen Connection String (auch DSN, Data Source Name), der alle Verbindungsparameter kodiert:

postgresql://username:password@host:port/database

Beispiel:

postgresql://app_user:secret@localhost:5432/school_db

Node.js-Anwendungen nutzen üblicherweise pg für PostgreSQL und mysql2 für MariaDB / MySQL.

Terminal-Fenster
npm install pg
import pg from 'pg';
const { Pool } = pg;
const pool = new Pool({
host: process.env.DB_HOST,
port: process.env.DB_PORT || 5432,
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
});
async function getActiveStudents() {
const result = await pool.query(
'SELECT student_id, name FROM students WHERE is_active = $1 ORDER BY name',
[true] // parameterized - $1 is the placeholder
);
return result.rows;
}
getActiveStudents().then(console.log);

Zu beachten ist, dass die Platzhalter in Node.js je nach Treiber unterschiedlich sind: PostgreSQL (pg) nutzt $1, $2, …, während MariaDB / MySQL (mysql2) ? verwendet.

async function createStudent(name) {
const result = await pool.query(
'INSERT INTO students (name, is_active) VALUES ($1, $2) RETURNING student_id',
[name, true]
);
return result.rows[0].student_id;
}
async function transferCredits(fromId, toId, amount) {
const client = await pool.connect();
try {
await client.query('BEGIN');
await client.query(
'UPDATE accounts SET balance = balance - $1 WHERE account_id = $2',
[amount, fromId]
);
await client.query(
'UPDATE accounts SET balance = balance + $1 WHERE account_id = $2',
[amount, toId]
);
await client.query('COMMIT');
} catch (err) {
await client.query('ROLLBACK');
throw err;
} finally {
client.release(); // return the client to the pool
}
}

Bei großen Ergebnismengen sollte man nicht alles auf einmal in den Speicher laden. Für UI-/API-Antworten dient Pagination, für Exporte Streaming bzw. Cursor.

const pageSize = 50;
const page = 0;
const offset = page * pageSize;
const result = await pool.query(
`SELECT student_id, name
FROM students
ORDER BY student_id
LIMIT $1 OFFSET $2`,
[pageSize, offset]
);
return result.rows;

Keyset-Pagination (empfohlen für große Tabellen)

Abschnitt betitelt „Keyset-Pagination (empfohlen für große Tabellen)“

Keyset-Pagination ist meist schneller und stabiler als große Offsets, weil sie den zuletzt gesehenen Schlüssel nutzt.

const lastSeenId = 1200;
const pageSize = 50;
const result = await pool.query(
`SELECT student_id, name
FROM students
WHERE student_id > $1
ORDER BY student_id
LIMIT $2`,
[lastSeenId, pageSize]
);
return result.rows;
  • Mit pg und mysql2 liefern normale Query-Aufrufe die gesamte Ergebnismenge in den Speicher.
  • Für sehr große Exporte streaming- oder cursorbasierten Zugriff verwenden und Zeilen in Blöcken verarbeiten.
  • Immer einen Index auf den in WHERE und ORDER BY genutzten Spalten für die Pagination halten.

PHPs PDO (PHP Data Objects) ist eine Datenbank-Abstraktionsschicht ähnlich ODBC. Es arbeitet mit mehreren RDBMS-Backends.

<?php
$dsn = 'pgsql:host=localhost;port=5432;dbname=school_db';
$user = getenv('DB_USER');
$pass = getenv('DB_PASSWORD');
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$stmt = $pdo->prepare('SELECT name FROM students WHERE student_id = :id');
$stmt->execute([':id' => 42]);
$student = $stmt->fetch(PDO::FETCH_ASSOC);
echo $student['name'];
?>

Für den Zugriff aus Python eignet sich dieses minimale Setup:

Terminal-Fenster
pip install psycopg2-binary python-dotenv
from dotenv import load_dotenv
import os
import psycopg2
load_dotenv()
conn = psycopg2.connect(
host=os.environ["DB_HOST"],
port=int(os.environ.get("DB_PORT", 5432)),
dbname=os.environ["DB_NAME"],
user=os.environ["DB_USER"],
password=os.environ["DB_PASSWORD"]
)
with conn:
with conn.cursor() as cur:
cur.execute("SELECT student_id, name FROM students WHERE name = %s", ("Anna",))
print(cur.fetchall())
import java.sql.*;
String url = "jdbc:postgresql://localhost:5432/school_db";
String user = System.getenv("DB_USER");
String password = System.getenv("DB_PASSWORD");
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement stmt = conn.prepareStatement(
"SELECT name FROM students WHERE student_id = ?")) {
stmt.setInt(1, 42);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
System.out.println(rs.getString("name"));
}
}
}

ODBC erlaubt Desktop-Werkzeugen wie Excel oder Power BI, sich direkt mit PostgreSQL und MariaDB / MySQL zu verbinden:

  1. Den PostgreSQL-ODBC-Treiber (psqlODBC) unter Windows installieren.
  2. ODBC-Datenquellen in Windows öffnen und einen neuen DSN (Data Source Name) anlegen.
  3. In Excel unter Daten → Daten abrufen → Aus Datenbank → Aus ODBC den DSN auswählen.
  4. In Power BI Daten abrufen → ODBC wählen und den DSN auswählen.

Statt vorab einen DSN im ODBC-Administrator zu konfigurieren, lassen sich alle Verbindungsparameter direkt in den Connection String der Anwendung einbetten:

DRIVER={PostgreSQL Unicode};SERVER=localhost;PORT=5432;DATABASE=school_db;UID=app_user;PWD=secret;

Das erspart die manuelle DSN-Einrichtung auf jedem Rechner und ist nützlich für automatisierte Deployments oder wenn die Anwendung an viele Nutzer verteilt wird.

Für PostgreSQL kommt psqlODBC in zwei Varianten:

  • PostgreSQL Unicode — behandelt UTF-8 und internationale Zeichen korrekt. Immer diese bevorzugen.
  • PostgreSQL ANSI — Altvariante für ältere Anwendungen, die ausdrücklich ANSI-Kodierung verlangen.

Für MariaDB / MySQL einen modernen, Unicode-fähigen ODBC-Treiber wählen (etwa MariaDB Connector/ODBC Unicode oder MySQL Connector/ODBC Unicode), sofern nicht eine ältere reine ANSI-Umgebung etwas anderes verlangt.

Beim Anlegen eines DSN im ODBC-Administrator wählt man zwischen zwei Geltungsbereichen:

TypSichtbar fürTypischer Einsatz
User-DSNnur den aktuellen Windows-Benutzerpersönliche Werkzeuge, Entwicklung
System-DSNalle Nutzer und Windows-Dienstegemeinsam genutzte Anwendungen, Dienste

Windows-Dienste (etwa ein Hintergrund-Sync-Job) laufen unter einem Dienstkonto und sehen User-DSNs meist nicht. Für serverseitige oder gemeinsam genutzte Anwendungen immer einen System-DSN verwenden.

psqlODBC unterstützt den Parameter sslmode, passend zu den Standard-SSL-Modi von PostgreSQL:

sslmode-WertVerhalten
disablekein SSL (Klartext)
requireSSL erforderlich, Zertifikat nicht geprüft
verify-caSSL + Serverzertifikat gegen eine CA prüfen
verify-fullSSL + Zertifikat und Hostname prüfen

Füge ihn den erweiterten DSN-Optionen oder einem DSN-losen Connection String hinzu:

...;SSLmode=require;

In jeder Produktions- oder Netzwerkumgebung mindestens require verwenden.

System-DSNs speichern den Benutzernamen (und optional das Passwort) in der Windows-Registry. Das Passwort ist für lokale Administratoren sichtbar. Für Produktivsysteme:

  • Das Passwort nicht im DSN speichern.
  • Die Anwendung oder den Nutzer das Passwort zur Verbindungszeit angeben lassen (Abfrage).
  • Alternativ Windows-integrierte Authentifizierung (SSPI/Kerberos) nutzen, wenn der PostgreSQL-Server dafür konfiguriert ist.

Standardmäßig können ODBC-Verbindungen und -Abfragen bei Netzwerkproblemen unbegrenzt hängen. Diese Parameter gehören in den DSN oder Connection String:

  • LoginTimeout — Sekunden, die beim Verbindungsaufbau gewartet wird (z. B. LoginTimeout=10).
  • QueryTimeout — Sekunden, bevor eine laufende Abfrage abgebrochen wird (in den meisten Treibern pro Statement konfigurierbar).

Ohne Timeouts kann eine unterbrochene Netzwerkverbindung eine Excel-Tabelle oder Anwendung unbegrenzt einfrieren.

Plattformübergreifende Hinweise (Windows, macOS, Linux)

Abschnitt betitelt „Plattformübergreifende Hinweise (Windows, macOS, Linux)“

Das ODBC-Konzept existiert auf allen großen Betriebssystemen, aber die Einrichtung unterscheidet sich:

ThemaWindowsmacOSLinux
ODBC-Managereingebauter ODBC-Administratormeist unixODBC oder iODBCmeist unixODBC
DSN-SpeicherungRegistry (User-/System-DSN)~/.odbc.ini und /etc/odbc.ini (üblich)~/.odbc.ini und /etc/odbc.ini
TreiberinstallationMSI/EXE-InstallerHomebrew/PKG (treiberabhängig)Paketmanager + Konfigurationsdateien
Plattform-Falle32-Bit vs. 64-Bit passt nichtIntel vs. Apple Silicon (x86_64 vs. arm64)fehlende Shared Libraries / Treiberpfade

Weitere praktische Punkte:

  • Bitness/Architektur muss passen: Unter Windows müssen App und Treiber beide 32-Bit oder beide 64-Bit sein. Unter macOS die native Architektur prüfen (arm64 auf Apple Silicon), um Rosetta-Probleme zu vermeiden.
  • Unterschiede bei Treibermanagern: unixODBC und iODBC werden nicht gleich konfiguriert. Bei Anleitungen immer die für den tatsächlich installierten Manager passenden Schritte verwenden.
  • Rechte zählen auf Unix-artigen Systemen: Ein DSN in /etc/odbc.ini braucht zum Bearbeiten eventuell erhöhte Rechte; benutzerspezifische DSNs in ~/.odbc.ini sind für die Entwicklung oft besser.
  • SSL-Zertifikate unterscheiden sich je OS: Truststore und Zertifikatspfade werden unterschiedlich gehandhabt. Funktioniert TLS auf einem OS, aber nicht auf einem anderen, zuerst CA-Pfad/Zertifikatskonfiguration prüfen.
  • Verfügbarkeit von BI-Desktop-Werkzeugen unterscheidet sich: Power BI Desktop ist primär Windows-basiert, unter macOS/Linux nutzt man oft Alternativen oder Gateways.
AnsatzTypischer EinsatzPortabilitätPerformanceKomplexität
Nativer Treiber (psycopg2, pg)Python-/Node.js-Web-Appsniedrig (DB-spezifisch)hochniedrig
ODBCDesktop-Werkzeuge, Multi-DB-Appshochmittelmittel
JDBCJava-Enterprise-Appshoch (über Treiber)hochmittel
ORM (SQLAlchemy, Prisma)schnelle Entwicklung, CRUD-Appshochmittelniedrig–mittel
PDO (PHP)PHP-Web-Appsmittelmittelniedrig

6. Sicherheits-Checkliste für Datenbank-Schnittstellen

Abschnitt betitelt „6. Sicherheits-Checkliste für Datenbank-Schnittstellen“

Sicherer Datenbankzugriff ist ein kritischer Teil der Anwendungssicherheit. Vor dem Produktivgang prüfen:

Datenbank-Schnittstellen sind die Brücke zwischen Anwendungscode und Datenbank-Engine. Die wichtigsten Punkte:

  • Native Treiber (psycopg2, pg) sind die häufigste Wahl für Python- und Node.js-Anwendungen. ODBC/JDBC bringen Portabilität über RDBMS-Hersteller hinweg. ORMs bieten eine höhere Abstraktion.
  • Immer parametrisierte Abfragen verwenden, um SQL-Injection zu verhindern.
  • Connection Pools in jeder Mehrbenutzer- oder Web-Anwendung einsetzen.
  • Zugangsdaten in Umgebungsvariablen speichern, nie im Quellcode.
  • Das Prinzip Least Privilege anwenden: Der Anwendungsbenutzer sollte nur die minimal nötigen Datenbankrechte haben.
  • Bei der Fehlersuche sowohl den Anwendungsfehler als auch das PostgreSQL-Server-Log prüfen, um das ganze Bild zu bekommen.