Python unter Linux: Datenbanken

In diesem Kapitel geht es um die Ansteuerung von Datenbankmanagementsystemen, kurz DBMS. Sie dienen dazu, Daten dauerhaft zu speichern und mit Hilfe einer eigenen Sprache, zumeist SQL, selektiv abzufragen. Im Regal EDV bei Wikibooks finden Sie einige Bücher zum Thema Datenbanken und SQL. Wir verwenden die Begriffe DBMS und Datenbanken in den folgenden Abschnitten synonym.

Wir stellen einige Datenbanksysteme vor und zeigen kurz, wie diese Systeme in Python angesteuert werden. Es geht uns hierbei insbesondere nicht um die Darstellung der Abfragesprache.

SQLite ist eine Datenbank, die auf einer einzelnen Datei basiert. Es muss kein Server installiert werden, dafür ist es nur schwer möglich, dass verschiedene Anwendungen gleichzeitig auf eine Datenbank zugreifen. Für Webapplikationen eignet sich dieses System nicht so gut wie andere hier vorgestellte Datenbanksysteme. Dafür sind Datenbanken schnell und ohne lästigen Ballast eingerichtet. Der Zugriff erfolgt mit Hilfe einiger weniger API-Funktionen. Das folgende Beispiel legt eine Datenbank als Datei an, fragt den Nutzer nach Eingaben und speichert diese Eingaben in der Datenbank. STRG-C bricht die Eingabe ab.

#!/usr/bin/python
# -*- encoding: utf-8 -*-

import sqlite3

con = sqlite3.connect('sl1.db')
con.isolation_level = None

con.execute("CREATE TABLE IF NOT EXISTS tiere (name TEXT, farbe TEXT)")

try:
    while True:
        tier = raw_input("(Abbruch mit STRG-C) Sag mir mal ein Tier> ")
        farbe = raw_input("Welche Farbe hat \"%s\"? > " % tier)
        con.execute("INSERT INTO tiere(name, farbe) VALUES(?, ?)", (tier, farbe))
except:
    print ; print

rows = con.execute("SELECT * FROM tiere")
print "Meine Lieblingstiere:"
for row in rows:
    print row[0], "hat die Farbe", row[1]
  Ausgabe

user@localhost:~$ ./sl1.py
(Abbruch mit STRG-C) Sag mir mal ein Tier> Maus
Welche Farbe hat "Maus"? > mausgrau
(Abbruch mit STRG-C) Sag mir mal ein Tier> Bär
Welche Farbe hat "Bär"? > braun
(Abbruch mit STRG-C) Sag mir mal ein Tier> Delfin
Welche Farbe hat "Delfin"? > blau-grau
(Abbruch mit STRG-C) Sag mir mal ein Tier>STRG-C

Meine Lieblingstiere:
Maus hat die Farbe mausgrau
Bär hat die Farbe braun
Delfin hat die Farbe blau-grau

Mit connect() wird die Verbindung zu einer SQLite3-Datei hergestellt. Falls keine Datei gewünscht wird, kann durch den Parameter :memory: die Datenbank auch im verfügbaren Speicher angelegt werden. Zurückgegeben wird ein so genanntes "Connection-Object".

SQLite3 ist transaktionsbasiert. Wir müssten bei allen die Datenbank ändernden Zugriffen wie INSERT ein Commit durchführen, durch die Angabe von isolation_level = None wird die DBMS in den Autocommit-Modus gesetzt, Änderungen werden also sofort geschrieben.

execute() führt ein SQL-Statement aus. Ein solches Statement kann Parameter beinhalten, die in SQL als Fragezeichen[1] geschrieben werden. Die Parameter werden als Tupel übergeben. execute() gibt ein so genanntes Cursor-Objekt zurück. Bei SELECT-Abfragen können wir dieses nutzen, um über alle abgefragten Zeilen zu iterieren.

Wir stellen ihnen hier ein Beispiel vor, bei dem auf eine entfernte Datenbank zugegriffen wird:

#!/usr/bin/python

import MySQLdb

db = MySQLdb.connect("anderer.host.entf3rnt.de","Tandar","ge431m","meine_datenbank")
cursor = db.cursor()
cursor.execute("SELECT VERSION()")
row = cursor.fetchone()
print "server version:", row[0]
cursor.close()
db.close()
  Ausgabe

user@localhost:~$ ./my1.py
server version: 5.0.32-Debian_7etch8-log

Die Verbindung wird hier erzeugt mit connect(). Der entfernte Server, der Benutzername, das Passwort und die eigentliche Datenbank, mit der wir uns verbinden wollen, werden als Parameter übergeben. Zurück erhalten wir einen Datenbankhandle oder eine Exception, wenn etwas schief ging.

Anschließend besorgen wir uns ein Cursor-Objekt, mit dessen Hilfe wir Abfragen formulieren können (execute("SELECT VERSION()")) und eine Ergebniszeile erhalten (fetchone()).

Die Ausgabezeile können wir sodann sofort ausgeben. Zum Schluss wird der Cursor wie auch die Verbindung zur Datenbank jeweils mit close() geschlossen.


Das nun folgende Beispiel ergänzt das obere Beispiel um die Fähigkeit, eine Tabelle anzulegen, Daten hineinzuschreiben und diese anschließend zu selektieren:

#!/usr/bin/python
# -*- encoding: utf-8 -*-

import MySQLdb

db = MySQLdb.connect("anderer.host.entf3rnt.de","Tandar","ge431m","meine_datenbank")
cursor = db.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS bar(uid int, anmeldedatum date)")
cursor.execute("INSERT INTO bar values(0, '2009-04-17')")
cursor.execute("INSERT INTO bar values(0, '2009-03-13')")
cursor.execute("INSERT INTO bar values(500, '2009-04-16')")
cursor.close()
db.commit()

db.query("SELECT uid, anmeldedatum FROM bar WHERE uid=0")
result = db.store_result()

nZeilen = result.num_rows()
nSpalten = result.num_fields()

print "Anzahl Zeilen:", nZeilen, "Anzahl Spalten:", nSpalten

for zeile in xrange(nZeilen):
    row = result.fetch_row()
    uid, datum = row[0]
    print uid, datum
db.close()
  Ausgabe

user@localhost:~$ ./my2.py
Anzahl Zeilen: 2 Anzahl Spalten: 2
0 2009-04-17
0 2009-03-13

Anders als im oberen Beispiel nutzen wir query(), um eine Anfrage an die Datenbank zu senden. Wir können das Ergebnis dieser Abfrage mit store_result() speichern und erhalten so die Ergebnismenge als Speicherobjekt zurück. Alternativ können wir use_result() verwenden, um die Ergebniszeilen nach und nach zu erhalten.

Mit num_rows() und num_fields() ermitteln wir die Anzahl der Ergebniszeilen und die Anzahl der Felder pro Zeile.

fetch_row() entnimmt der Ergebnismenge eine Zeile und liefert sie als Zeilentupel heraus. Die einzelnen Felder (hier uid und datum) sind selbst ein Tupel im ersten Element der Zeile.

AnyDBM ist ein Modul, welches sich mit DBM-ähnlichen Datenbanken beschäftigt. Von dieser Sorte gibt es zwei Stück[2], nämlich DBM und GNU-DBM. Diese unterscheiden sich in ihrem internen Aufbau und der Lizenz, sind aber ansonsten gleich.

DBM-Datenbanken sind eine Art von Wörterbüchern, sie speichern String-Dictionaries ab. Folgendes Beispiel zeigt die grundsätzliche Arbeitsweise mit ihnen:

#!/usr/bin/python
# -*- encoding: utf-8 -*-

import anydbm

db = anydbm.open("wertpapiere.gdbm", "c", 0660)
db["Siemens"] = "1000"
db["Apple"] = "2000"
db["Red Hat"] = "3000"
db.close()

db = anydbm.open("wertpapiere.gdbm", "r")
for key, value in db.iteritems():
    print "Von der Aktie", key, "habe ich", value, "Stück"
db.close()
  Ausgabe

user@localhost:~$ ./dbm1.py
Von der Aktie Apple habe ich 2000 Stück
Von der Aktie Red Hat habe ich 3000 Stück
Von der Aktie Siemens habe ich 1000 Stück

Man kann nur Strings speichern. Mit open(dateiname, art, dateiflags) wird eine solche Datei angelegt oder gelesen. Die art ist "c" zum Erzeugen der Datenbank, wenn sie nicht existiert, "w" zum Schreiben, "r" zum Lesen. dateiflags ist ein numerischer Wert, der, in Abhängigkeit von der aktuellen umask[3], den Dateimodus spezifiziert.

Die Werte werden wie in einem Dictionary eingetragen, anschließend wird die Datei mit close() wieder geschlossen. Über die Schlüssel-Wertpaare kann man mit der Methode iteritems() iterieren.

Zusammenfassung

Bearbeiten

In diesem Kapitel haben wir einige Datenbanken kennen gelernt und die typische Arbeitsweise mit ihnen aufgezeigt.

Anmerkungen

Bearbeiten
  1. Dieses ist sogleich die sichere Variante, sie schützt gut vor SQL-Injection.
  2. Soweit wir wissen...
  3. Siehe die Manual-Seite zu bash(1)