PEP 249 – Python Database API Spezifikation v2.0
- Autor:
- Marc-André Lemburg <mal at lemburg.com>
- Discussions-To:
- Db-SIG Liste
- Status:
- Final
- Typ:
- Informational
- Erstellt:
- 12-Apr-1999
- Post-History:
- Ersetzt:
- 248
Inhaltsverzeichnis
- Einleitung
- Modulschnittstelle
- Connection-Objekte
- Cursor-Objekte
- Typ-Objekte und Konstruktoren
- Implementierungshinweise für Modulautoren
- Optionale DB API Erweiterungen
- Optionale Fehlerbehandlungs-Erweiterungen
- Optionale Two-Phase Commit Erweiterungen
- Häufig gestellte Fragen
- Wesentliche Änderungen von Version 1.0 auf Version 2.0
- Offene Fragen
- Fußnoten
- Danksagungen
- Urheberrecht
Einleitung
Diese API wurde definiert, um die Ähnlichkeit zwischen den für den Datenbankzugriff verwendeten Python-Modulen zu fördern. Auf diese Weise hoffen wir, eine Konsistenz zu erreichen, die zu leichter verständlichen Modulen, generell portablerem Code über verschiedene Datenbanken hinweg und einer breiteren Reichweite der Datenbankkonnektivität aus Python heraus führt.
Kommentare und Fragen zu dieser Spezifikation können an die SIG für Datenbankanbindung mit Python gerichtet werden.
Weitere Informationen zur Datenbankanbindung mit Python und verfügbaren Paketen finden Sie im Datenbank-Themenführer.
Dieses Dokument beschreibt die Python Database API Spezifikation 2.0 und eine Reihe gemeinsamer optionaler Erweiterungen. Die vorherige Version 1.0 ist noch als Referenz in PEP 248 verfügbar. Paketautoren werden ermutigt, diese Version der Spezifikation als Grundlage für neue Schnittstellen zu verwenden.
Modulschnittstelle
Konstruktoren
Der Zugriff auf die Datenbank wird über Connection-Objekte ermöglicht. Das Modul muss den folgenden Konstruktor dafür bereitstellen
- connect( parameter… )
- Konstruktor zum Erstellen einer Verbindung zur Datenbank.
Gibt ein Connection-Objekt zurück. Er nimmt eine Reihe von Parametern entgegen, die datenbankabhängig sind. [1]
Globale Variablen
Diese globalen Modulvariablen müssen definiert sein
- apilevel
- Zeichenkettenkonstante, die das unterstützte DB API-Level angibt.
Derzeit sind nur die Zeichenketten „
1.0“ und „2.0“ zulässig. Wenn nicht angegeben, sollte eine DB-API 1.0-Schnittstelle angenommen werden.
- threadsafety
- Ganzzahlkonstante, die das Level der Thread-Sicherheit angibt, das die Schnittstelle unterstützt. Mögliche Werte sind
threadsafety Bedeutung 0 Threads dürfen das Modul nicht gemeinsam nutzen. 1 Threads dürfen das Modul, aber keine Verbindungen gemeinsam nutzen. 2 Threads dürfen das Modul und Verbindungen gemeinsam nutzen. 3 Threads dürfen das Modul, Verbindungen und Cursor gemeinsam nutzen. Gemeinsame Nutzung im obigen Kontext bedeutet, dass zwei Threads eine Ressource nutzen können, ohne sie mit einem Mutex-Semaphore zur Implementierung von Ressourcensperren zu umschließen. Beachten Sie, dass externe Ressourcen nicht immer durch die Verwaltung des Zugriffs mit einem Mutex-Mechanismus threadsicher gemacht werden können: Die Ressource kann von globalen Variablen oder anderen externen Quellen abhängen, die außerhalb Ihrer Kontrolle liegen.
- paramstyle
- Zeichenkettenkonstante, die die Art der Parameterkennzeichnungsformatierung angibt, die von der Schnittstelle erwartet wird. Mögliche Werte sind [2]
paramstyle Bedeutung qmarkFragezeichen-Stil, z.B. ...WHERE name=?numericNumerischer, positioneller Stil, z.B. ...WHERE name=:1namedBenannter Stil, z.B. ...WHERE name=:nameformatANSI C printf-Formatcodes, z.B. ...WHERE name=%spyformatPython-erweiterte Formatcodes, z.B. ...WHERE name=%(name)s
Ausnahmen
Das Modul sollte alle Fehlerinformationen über diese Ausnahmen oder davon abgeleitete Klassen zugänglich machen
- Warnung
- Ausnahme, die für wichtige Warnungen ausgelöst wird, wie z.B. Datenabschneidungen beim Einfügen usw. Sie muss eine Unterklasse der Python
Exception-Klasse sein [10] [11].
- Error
- Ausnahme, die die Basisklasse aller anderen Fehlerausnahmen ist. Sie können diese verwenden, um alle Fehler mit einer einzigen
except-Anweisung abzufangen. Warnungen gelten nicht als Fehler und sollten daher diese Klasse nicht als Basis verwenden. Sie muss eine Unterklasse der PythonException-Klasse sein [10].
- InterfaceError
- Ausnahme, die für Fehler ausgelöst wird, die sich auf die Datenbank-Schnittstelle und nicht auf die Datenbank selbst beziehen. Sie muss eine Unterklasse von Error sein.
- DatabaseError
- Ausnahme, die für Fehler ausgelöst wird, die sich auf die Datenbank beziehen. Sie muss eine Unterklasse von Error sein.
- DataError
- Ausnahme, die für Fehler ausgelöst wird, die auf Probleme mit den verarbeiteten Daten zurückzuführen sind, wie z.B. Division durch Null, numerischer Wert außerhalb des Bereichs usw. Sie muss eine Unterklasse von DatabaseError sein.
- OperationalError
- Ausnahme, die für Fehler ausgelöst wird, die sich auf den Betrieb der Datenbank beziehen und nicht unbedingt unter der Kontrolle des Programmierers stehen, z.B. eine unerwartete Trennung, die Datenquellen-Name nicht gefunden, eine Transaktion konnte nicht verarbeitet werden, ein Speicherzuordnungsfehler trat während der Verarbeitung auf usw. Sie muss eine Unterklasse von DatabaseError sein.
- IntegrityError
- Ausnahme, die ausgelöst wird, wenn die relationale Integrität der Datenbank beeinträchtigt wird, z.B. ein Fremdschlüssel-Check schlägt fehl. Sie muss eine Unterklasse von DatabaseError sein.
- InternalError
- Ausnahme, die ausgelöst wird, wenn die Datenbank einen internen Fehler feststellt, z.B. der Cursor ist nicht mehr gültig, die Transaktion ist außer sync usw. Sie muss eine Unterklasse von DatabaseError sein.
- ProgrammingError
- Ausnahme, die für Programmierfehler ausgelöst wird, z.B. Tabelle nicht gefunden oder bereits vorhanden, Syntaxfehler in der SQL-Anweisung, falsche Anzahl von Parametern angegeben usw. Sie muss eine Unterklasse von DatabaseError sein.
- NotSupportedError
- Ausnahme, die ausgelöst wird, wenn eine Methode oder DB API verwendet wurde, die von der Datenbank nicht unterstützt wird, z.B. Anforderung eines .rollback() auf einer Verbindung, die keine Transaktionen unterstützt oder Transaktionen ausgeschaltet hat. Sie muss eine Unterklasse von DatabaseError sein.
Dies ist das Vererbungsschema der Ausnahmen [10] [11]
Exception
|__Warning
|__Error
|__InterfaceError
|__DatabaseError
|__DataError
|__OperationalError
|__IntegrityError
|__InternalError
|__ProgrammingError
|__NotSupportedError
Hinweis
Die Werte dieser Ausnahmen sind nicht definiert. Sie sollten dem Benutzer jedoch eine ziemlich gute Vorstellung davon geben, was schief gelaufen ist.
Connection-Objekte
Connection-Objekte sollten auf die folgenden Methoden reagieren.
Connection-Methoden
- .close()
- Schließt die Verbindung jetzt (anstatt wann immer
.__del__()aufgerufen wird).Die Verbindung ist ab diesem Zeitpunkt unbrauchbar; eine Error (oder Unterklasse)-Ausnahme wird ausgelöst, wenn eine Operation mit der Verbindung versucht wird. Dasselbe gilt für alle Cursor-Objekte, die versuchen, die Verbindung zu nutzen. Beachten Sie, dass das Schließen einer Verbindung, ohne die Änderungen vorher zu committen, einen impliziten Rollback zur Folge hat.
- .commit()
- Committet alle ausstehenden Transaktionen zur Datenbank.
Beachten Sie, dass, wenn die Datenbank eine Auto-Commit-Funktion unterstützt, diese zunächst ausgeschaltet sein muss. Eine Schnittstellenmethode kann bereitgestellt werden, um sie wieder einzuschalten.
Datenbankmodule, die keine Transaktionen unterstützen, sollten diese Methode mit leerer Funktionalität implementieren.
- .rollback()
- Diese Methode ist optional, da nicht alle Datenbanken Transaktionsunterstützung bieten. [3]
Falls eine Datenbank Transaktionen anbietet, bewirkt diese Methode, dass die Datenbank zu Beginn jeder ausstehenden Transaktion zurückgerollt wird. Das Schließen einer Verbindung, ohne die Änderungen vorher zu committen, führt zu einem impliziten Rollback.
- .cursor()
- Gibt ein neues Cursor-Objekt zurück, das die Verbindung verwendet.
Wenn die Datenbank kein direktes Cursor-Konzept anbietet, muss das Modul Cursor auf andere Weise emulieren, soweit dies für diese Spezifikation erforderlich ist. [4]
Cursor-Objekte
Diese Objekte stellen einen Datenbank-Cursor dar, der zur Verwaltung des Kontexts einer Abfrageoperation verwendet wird. Cursor, die von derselben Verbindung erstellt wurden, sind nicht isoliert, d.h. alle Änderungen, die von einem Cursor an der Datenbank vorgenommen werden, sind für andere Cursor sofort sichtbar. Cursor, die von verschiedenen Verbindungen erstellt wurden, können isoliert sein oder auch nicht, je nachdem, wie die Transaktionsunterstützung implementiert ist (siehe auch die Methoden .rollback() und .commit() der Verbindung).
Cursor-Objekte sollten auf die folgenden Methoden und Attribute reagieren.
Cursor-Attribute
- .description
- Dieses schreibgeschützte Attribut ist eine Sequenz von 7-elementigen Sequenzen.
Jede dieser Sequenzen enthält Informationen, die eine Ergebnissspalte beschreiben
nametype_codedisplay_sizeinternal_sizeprecisionscalenull_ok
Die ersten beiden Elemente (
nameundtype_code) sind obligatorisch, die anderen fünf sind optional und werden aufNonegesetzt, wenn keine aussagekräftigen Werte bereitgestellt werden können.Dieses Attribut ist
Nonefür Operationen, die keine Zeilen zurückgeben, oder wenn für den Cursor noch keine Operation über die Methode .execute*() aufgerufen wurde.Der
type_codekann durch Vergleich mit den Typ-Objekten interpretiert werden, die im folgenden Abschnitt angegeben sind.
- .rowcount
- Dieses schreibgeschützte Attribut gibt die Anzahl der Zeilen an, die die letzte .execute*()-Operation erzeugt hat (für DQL-Anweisungen wie
SELECT) oder beeinflusst hat (für DML-Anweisungen wieUPDATEoderINSERT). [9]Das Attribut ist -1, wenn noch keine .execute*()-Operation auf dem Cursor ausgeführt wurde oder wenn die Zeilenanzahl der letzten Operation von der Schnittstelle nicht ermittelt werden kann. [7]
Hinweis
Zukünftige Versionen der DB API Spezifikation könnten den letzteren Fall so umdefinieren, dass das Objekt stattdessen
Nonezurückgibt.
Cursor-Methoden
- .callproc( procname [, parameter ] )
- (Diese Methode ist optional, da nicht alle Datenbanken gespeicherte Prozeduren anbieten. [3])
Ruft eine gespeicherte Datenbankprozedur mit dem angegebenen Namen auf. Die Parametersequenz muss einen Eintrag für jedes Argument enthalten, das die Prozedur erwartet. Das Ergebnis des Aufrufs wird als modifizierte Kopie der Eingabesequenz zurückgegeben. Eingabeparameter bleiben unverändert, Ausgabe- und Ein-/Ausgabeparameter werden durch möglicherweise neue Werte ersetzt.
Die Prozedur kann auch einen Ergebnissatz als Ausgabe liefern. Dieser muss dann über die Standardmethoden .fetch*() zugänglich gemacht werden.
- .close()
- Schließt den Cursor jetzt (anstatt wann immer
__del__aufgerufen wird).Der Cursor ist ab diesem Zeitpunkt unbrauchbar; eine Error (oder Unterklasse)-Ausnahme wird ausgelöst, wenn eine Operation mit dem Cursor versucht wird.
- .execute(operation [, parameter])
- Bereitet eine Datenbankoperation (Abfrage oder Befehl) vor und führt sie aus.
Parameter können als Sequenz oder Mapping bereitgestellt werden und werden an Variablen in der Operation gebunden. Variablen werden in einer datenbankspezifischen Notation angegeben (siehe das Attribut paramstyle des Moduls für Details). [5]
Eine Referenz auf die Operation wird vom Cursor beibehalten. Wenn dasselbe Operations-Objekt erneut übergeben wird, kann der Cursor sein Verhalten optimieren. Dies ist am effektivsten für Algorithmen, bei denen dieselbe Operation verwendet wird, aber unterschiedliche Parameter an sie gebunden werden (viele Male).
Für maximale Effizienz bei der Wiederverwendung einer Operation ist es am besten, die Methode .setinputsizes() zu verwenden, um die Parametertypen und -größen im Voraus festzulegen. Es ist zulässig, dass ein Parameter nicht mit den vordefinierten Informationen übereinstimmt; die Implementierung sollte dies kompensieren, möglicherweise mit einem Effizienzverlust.
Die Parameter können auch als Liste von Tupeln angegeben werden, um z.B. mehrere Zeilen in einer einzigen Operation einzufügen, aber diese Art der Verwendung ist veraltet: stattdessen sollte .executemany() verwendet werden.
Rückgabewerte sind nicht definiert.
- .executemany( operation, seq_of_parameters )
- Bereitet eine Datenbankoperation (Abfrage oder Befehl) vor und führt sie dann für alle Parametersequenzen oder Mappings aus, die in der Sequenz seq_of_parameters gefunden werden.
Module können diese Methode mit mehreren Aufrufen von .execute() oder durch die Verwendung von Array-Operationen implementieren, um die Datenbank die Sequenz als Ganzes in einem Aufruf verarbeiten zu lassen.
Die Verwendung dieser Methode für eine Operation, die einen oder mehrere Ergebnissätze erzeugt, führt zu undefiniertem Verhalten, und die Implementierung darf (muss aber nicht) eine Ausnahme auslösen, wenn sie feststellt, dass durch einen Aufruf der Operation ein Ergebnissatz erzeugt wurde.
Die gleichen Kommentare wie für .execute() gelten entsprechend für diese Methode.
Rückgabewerte sind nicht definiert.
- .fetchone()
- Holt die nächste Zeile eines Abfrageergebnisses und gibt eine einzelne Sequenz zurück, oder
None, wenn keine weiteren Daten verfügbar sind. [6]Eine Error (oder Unterklasse)-Ausnahme wird ausgelöst, wenn der vorherige Aufruf von .execute*() kein Ergebnis erzeugt hat oder noch kein Aufruf erfolgt ist.
- .fetchmany([size=cursor.arraysize])
- Holt den nächsten Satz von Zeilen eines Abfrageergebnisses und gibt eine Sequenz von Sequenzen zurück (z.B. eine Liste von Tupeln). Eine leere Sequenz wird zurückgegeben, wenn keine weiteren Zeilen verfügbar sind.
Die Anzahl der Zeilen, die pro Aufruf abgerufen werden sollen, wird durch den Parameter angegeben. Wenn er nicht angegeben ist, bestimmt die
arraysizedes Cursors die Anzahl der abzurufenden Zeilen. Die Methode sollte versuchen, so viele Zeilen abzurufen, wie der Parameter angibt. Wenn dies aufgrund der nicht verfügbaren Anzahl von Zeilen nicht möglich ist, können weniger Zeilen zurückgegeben werden.Eine Error (oder Unterklasse)-Ausnahme wird ausgelöst, wenn der vorherige Aufruf von .execute*() kein Ergebnis erzeugt hat oder noch kein Aufruf erfolgt ist.
Beachten Sie, dass es Performance-Überlegungen gibt, die mit dem size-Parameter verbunden sind. Für optimale Leistung ist es normalerweise am besten, das Attribut .arraysize zu verwenden. Wenn der size-Parameter verwendet wird, ist es am besten, wenn er von einem Aufruf von .fetchmany() zum nächsten denselben Wert beibehält.
- .fetchall()
- Holt alle (verbleibenden) Zeilen eines Abfrageergebnisses und gibt sie als Sequenz von Sequenzen zurück (z.B. eine Liste von Tupeln). Beachten Sie, dass das
arraysize-Attribut des Cursors die Leistung dieser Operation beeinflussen kann.Eine Error (oder Unterklasse)-Ausnahme wird ausgelöst, wenn der vorherige Aufruf von .execute*() kein Ergebnis erzeugt hat oder noch kein Aufruf erfolgt ist.
- .nextset()
- (Diese Methode ist optional, da nicht alle Datenbanken mehrere Ergebnissätze unterstützen. [3])
Diese Methode bewirkt, dass der Cursor zum nächsten verfügbaren Satz springt und alle verbleibenden Zeilen aus dem aktuellen Satz verwirft.
Wenn keine weiteren Sätze vorhanden sind, gibt die Methode
Nonezurück. Andernfalls gibt sie einen wahren Wert zurück und nachfolgende Aufrufe der Methoden .fetch*() geben Zeilen aus dem nächsten Ergebnissatz zurück.Eine Error (oder Unterklasse)-Ausnahme wird ausgelöst, wenn der vorherige Aufruf von .execute*() kein Ergebnis erzeugt hat oder noch kein Aufruf erfolgt ist.
- .arraysize
- Dieses Lese-/Schreibattribut gibt die Anzahl der Zeilen an, die auf einmal mit .fetchmany() abgerufen werden. Es ist standardmäßig 1, was bedeutet, dass jeweils eine einzelne Zeile abgerufen wird.
Implementierungen müssen diesen Wert in Bezug auf die Methode .fetchmany() beachten, sind aber frei, zeilenweise mit der Datenbank zu interagieren. Er kann auch bei der Implementierung von .executemany() verwendet werden.
- .setinputsizes(größen)
- Dies kann vor einem Aufruf von .execute*() verwendet werden, um Speicherbereiche für die Parameter der Operation vorzudefinieren.
Größen werden als Sequenz angegeben – ein Element für jeden Eingabeparameter. Das Element sollte ein Typ-Objekt sein, das der zu verwendenden Eingabe entspricht, oder es sollte eine Ganzzahl sein, die die maximale Länge eines Zeichenkettenparameters angibt. Wenn das Element
Noneist, wird für diese Spalte kein vordefinierter Speicherbereich reserviert (dies ist nützlich, um vordefinierte Bereiche für große Eingaben zu vermeiden).Diese Methode würde vor dem Aufruf der Methode .execute*() verwendet werden.
Implementierungen können diese Methode frei haben, nichts zu tun, und Benutzer können sie frei nicht verwenden.
- .setoutputsize(größe [, spalte])
- Legt eine Puffergröße für das Abrufen großer Spalten (z.B.
LONGs,BLOBs usw.) fest. Die Spalte wird als Index in der Ergebnissequenz angegeben. Wenn die Spalte nicht angegeben wird, wird die Standardgröße für alle großen Spalten im Cursor festgelegt.Diese Methode würde vor dem Aufruf der Methode .execute*() verwendet werden.
Implementierungen können diese Methode frei haben, nichts zu tun, und Benutzer können sie frei nicht verwenden.
Typ-Objekte und Konstruktoren
Viele Datenbanken benötigen die Eingabe in einem bestimmten Format für die Bindung an die Eingabeparameter einer Operation. Wenn beispielsweise eine Eingabe für eine DATE-Spalte bestimmt ist, muss sie in einem bestimmten Zeichenkettenformat an die Datenbank gebunden werden. Ähnliche Probleme gibt es für „Row ID“-Spalten oder große binäre Elemente (z.B. Blobs oder RAW-Spalten). Dies stellt Probleme für Python dar, da die Parameter für die Methode .execute*() untyped sind. Wenn das Datenbankmodul ein Python-Zeichenkettenobjekt sieht, weiß es nicht, ob es als einfache CHAR-Spalte, als rohes BINARY-Element oder als DATE gebunden werden soll.
Um dieses Problem zu lösen, muss ein Modul die unten definierten Konstruktoren bereitstellen, um Objekte zu erstellen, die spezielle Werte enthalten können. Wenn diese an die Cursor-Methoden übergeben werden, kann das Modul den richtigen Typ des Eingabeparameters erkennen und ihn entsprechend binden.
Das Attribut description eines Cursor-Objekts gibt Informationen über jede der Ergebnissspalten einer Abfrage zurück. Der type_code muss mit einem der unten definierten Typ-Objekte übereinstimmen. Typ-Objekte können mit mehr als einem Typ-Code gleich sein (z.B. könnte DATETIME gleich den Typ-Codes für Datums-, Zeit- und Zeitstempelspalten sein; siehe die Implementierungshinweise unten für Details).
Das Modul exportiert die folgenden Konstruktoren und Singletons
- Date(jahr, monat, tag)
- Diese Funktion konstruiert ein Objekt, das einen Datumswert enthält.
- Time(stunde, minute, sekunde)
- Diese Funktion konstruiert ein Objekt, das einen Zeitwert enthält.
- Timestamp(jahr, monat, tag, stunde, minute, sekunde)
- Diese Funktion konstruiert ein Objekt, das einen Zeitstempelwert enthält.
- DateFromTicks(ticks)
- Diese Funktion konstruiert ein Objekt, das einen Datumswert aus dem angegebenen Ticks-Wert enthält (Anzahl der Sekunden seit der Epoche; siehe Dokumentation des standardmäßigen Python-Zeitmoduls für Details).
- TimeFromTicks(ticks)
- Diese Funktion konstruiert ein Objekt, das einen Zeitwert aus dem angegebenen Ticks-Wert enthält (Anzahl der Sekunden seit der Epoche; siehe Dokumentation des Standard-Python-Zeitmoduls für Details).
- TimestampFromTicks(ticks)
- Diese Funktion konstruiert ein Objekt, das einen Zeitstempelwert aus dem angegebenen Ticks-Wert enthält (Anzahl der Sekunden seit der Epoche; siehe Dokumentation des Standard-Python-Zeitmoduls für Details).
- Binary(zeichenkette)
- Diese Funktion konstruiert ein Objekt, das einen binären (langen) Zeichenkettenwert aufnehmen kann.
- STRING-Typ
- Dieses Typ-Objekt wird verwendet, um Spalten in einer Datenbank zu beschreiben, die zeichenkettenbasiert sind (z.B.
CHAR).
- BINARY-Typ
- Dieses Typ-Objekt wird verwendet, um (lange) binäre Spalten in einer Datenbank zu beschreiben (z.B.
LONG,RAW,BLOBs).
- NUMBER-Typ
- Dieses Typ-Objekt wird verwendet, um numerische Spalten in einer Datenbank zu beschreiben.
- DATETIME-Typ
- Dieses Typ-Objekt wird verwendet, um Datums-/Zeitspalten in einer Datenbank zu beschreiben.
- ROWID-Typ
- Dieses Typ-Objekt wird verwendet, um die „Row ID“-Spalte in einer Datenbank zu beschreiben.
SQL NULL-Werte werden bei der Eingabe und Ausgabe durch das Python-Singleton None repräsentiert.
Hinweis
Die Verwendung von Unix-Ticks für die Datenbankanbindung kann Probleme verursachen, da sie einen begrenzten Datumsbereich abdecken.
Optionale DB API Erweiterungen
Während der Lebensdauer von DB API 2.0 haben Modulautoren ihre Implementierungen oft über das hinaus erweitert, was diese DB API-Spezifikation verlangt. Um die Kompatibilität zu verbessern und einen sauberen Upgrade-Pfad zu zukünftigen Versionen der Spezifikation zu bieten, definiert dieser Abschnitt eine Reihe gemeinsamer Erweiterungen der Kern-DB API 2.0-Spezifikation.
Wie bei allen optionalen DB API-Funktionen steht es den Autoren von Datenbankmodulen frei, diese zusätzlichen Attribute und Methoden nicht zu implementieren (deren Verwendung führt dann zu einem AttributeError) oder eine NotSupportedError auszulösen, falls die Verfügbarkeit erst zur Laufzeit geprüft werden kann.
Es wurde vorgeschlagen, die Nutzung dieser Erweiterungen dem Programmierer optional sichtbar zu machen, indem Python-Warnungen über das Python-Warnungs-Framework ausgegeben werden. Um diese Funktion nutzbar zu machen, müssen die Warnmeldungen standardisiert sein, um sie maskieren zu können. Diese Standardmeldungen werden im Folgenden als Warnmeldung bezeichnet.
- Cursor.rownumber
- Dieses schreibgeschützte Attribut sollte den aktuellen 0-basierten Index des Cursors im Ergebnissatz liefern oder
None, wenn der Index nicht ermittelt werden kann.Der Index kann als Index des Cursors in einer Sequenz (dem Ergebnissatz) betrachtet werden. Der nächste Abrufoperation ruft die Zeile ab, die in dieser Sequenz durch .rownumber indiziert ist.
Warnmeldung: „DB-API-Erweiterung cursor.rownumber verwendet“
- Connection.Error, Connection.ProgrammingError, etc.
- Alle von der DB API-Norm definierten Ausnahmeklassen sollten auf den Connection-Objekten als Attribute (zusätzlich zur Verfügbarkeit auf Modul-Ebene) zugänglich gemacht werden.
Diese Attribute vereinfachen die Fehlerbehandlung in Umgebungen mit mehreren Verbindungen.
Warnmeldung: „DB-API-Erweiterung connection.<exception> verwendet“
- Cursor.connection
- Dieses schreibgeschützte Attribut gibt eine Referenz auf das Connection-Objekt zurück, auf dem der Cursor erstellt wurde.
Das Attribut vereinfacht das Schreiben von polymorphem Code in Umgebungen mit mehreren Verbindungen.
Warnmeldung: „DB-API-Erweiterung cursor.connection verwendet“
- Cursor.scroll(wert [, modus=’relative’ ])
- Scrollt den Cursor im Ergebnissatz an eine neue Position gemäß modus.
Wenn modus
relative(Standard) ist, wirdwertals Offset zur aktuellen Position im Ergebnissatz genommen, wenn aufabsolutegesetzt, gibtwerteine absolute Zielposition an.Eine
IndexErrorsollte ausgelöst werden, wenn ein Scroll-Vorgang den Ergebnissatz verlässt. In diesem Fall bleibt die Cursorposition undefiniert (ideal wäre es, den Cursor gar nicht zu bewegen).Hinweis
Diese Methode sollte native scrollbare Cursor verwenden, falls verfügbar, oder auf eine Emulation für vorwärts-only scrollbare Cursor zurückgreifen. Die Methode kann NotSupportedError auslösen, um anzuzeigen, dass eine bestimmte Operation von der Datenbank nicht unterstützt wird (z.B. Rückwärts-Scrolling).
Warnmeldung: „DB-API-Erweiterung cursor.scroll() verwendet“
- Cursor.messages
- Dies ist ein Python-Listenobjekt, dem die Schnittstelle Tupel (Ausnahmeklasse, Ausnahme-Wert) für alle Nachrichten anhängt, die die Schnittstelle von der zugrunde liegenden Datenbank für diesen Cursor empfängt.
Die Liste wird durch alle Standardaufrufe von Cursor-Methoden gelöscht (vor der Ausführung des Aufrufs) mit Ausnahme der .fetch*()-Aufrufe, um übermäßigen Speicherverbrauch zu vermeiden, und kann auch durch Ausführen von
del cursor.messages[:]gelöscht werden.Alle von der Datenbank generierten Fehler- und Warnmeldungen werden in diese Liste eingetragen, sodass die Überprüfung der Liste es dem Benutzer ermöglicht, den korrekten Betrieb der Methodenaufrufe zu verifizieren.
Ziel dieses Attributs ist es, die Notwendigkeit einer Warnungs-Ausnahme zu eliminieren, die oft Probleme verursacht (einige Warnungen haben nur informativen Charakter).
Warnmeldung: „DB-API-Erweiterung cursor.messages verwendet“
- Connection.messages
- Ähnlich wie bei Cursor.messages, nur dass die Nachrichten in der Liste verbindungsorientiert sind.
Die Liste wird automatisch durch alle Standardaufrufe von Verbindungs-Methoden gelöscht (vor der Ausführung des Aufrufs), um übermäßigen Speicherverbrauch zu vermeiden, und kann auch durch Ausführen von
del connection.messages[:]gelöscht werden.Warnmeldung: „DB-API-Erweiterung connection.messages verwendet“
- Cursor.next()
- Gibt die nächste Zeile aus der aktuell ausgeführten SQL-Anweisung zurück, mit denselben Semantik wie .fetchone(). Eine
StopIteration-Ausnahme wird ausgelöst, wenn das Ergebnissatz für Python-Versionen 2.2 und neuer erschöpft ist. Frühere Versionen haben keineStopIteration-Ausnahme und die Methode sollte stattdessen eineIndexErrorauslösen.Warnmeldung: „DB-API-Erweiterung cursor.next() verwendet“
- Cursor.__iter__()
- Gibt
selfzurück, um Cursor mit dem Iterationsprotokoll kompatibel zu machen [8].Warnmeldung: „DB-API-Erweiterung cursor.__iter__() verwendet“
- Cursor.lastrowid
- Dieses schreibgeschützte Attribut liefert die RowID der zuletzt geänderten Zeile (die meisten Datenbanken geben eine RowID nur bei einer einzelnen
INSERT-Operation zurück). Wenn die Operation keine RowID setzt oder die Datenbank keine RowIDs unterstützt, sollte dieses Attribut aufNonegesetzt werden.Die Semantik von
.lastrowidist undefiniert, wenn die zuletzt ausgeführte Anweisung mehr als eine Zeile geändert hat, z.B. bei Verwendung vonINSERTmit.executemany().Warnmeldung: „DB-API-Erweiterung cursor.lastrowid verwendet“
- Connection.autocommit
- Attribut zum Abfragen und Setzen des Autocommit-Modus der Verbindung.
Gibt
Truezurück, wenn die Verbindung im Autocommit-Modus (nicht transaktional) arbeitet. GibtFalsezurück, wenn die Verbindung im manuellen Commit-Modus (transaktional) arbeitet.Das Setzen des Attributs auf
TrueoderFalsepasst den Modus der Verbindung entsprechend an.Das Ändern der Einstellung von
TrueaufFalse(Deaktivieren von Autocommit) bewirkt, dass die Datenbank den Autocommit-Modus verlässt und eine neue Transaktion startet. Das Ändern vonFalseaufTrue(Aktivieren von Autocommit) hat datenbankabhängige Semantik in Bezug darauf, wie ausstehende Transaktionen behandelt werden. [12]Hinweis zur Veralterung: Obwohl mehrere Datenbankmodule sowohl die Lese- als auch die Schreibfunktionalität dieses Attributs implementieren, ist das Setzen des Autocommit-Modus durch Schreiben auf das Attribut veraltet, da dies zu E/A- und verwandten Ausnahmen führen kann, was die Implementierung in einem asynchronen Kontext erschwert. [13]
Warnmeldung: „DB-API-Erweiterung connection.autocommit verwendet“
Optionale Fehlerbehandlungs-Erweiterungen
Die Kern-DB API-Spezifikation führt nur eine Reihe von Ausnahmen ein, die ausgelöst werden können, um dem Benutzer Fehler zu melden. In einigen Fällen können Ausnahmen den Programmfluss zu stark stören oder die Ausführung sogar unmöglich machen.
Für diese Fälle und um die Fehlerbehandlung bei der Arbeit mit Datenbanken zu vereinfachen, können Modulautoren von Datenbanken optionale Fehlerbehandlungsmechanismen implementieren. Dieser Abschnitt beschreibt eine standardisierte Methode zur Definition dieser Fehlerbehandler.
- Connection.errorhandler, Cursor.errorhandler
- Lese-/Schreibattribut, das auf einen Fehlerbehandler verweist, der im Falle eines Fehlerzustands aufgerufen werden soll.
Der Handler muss ein Python-aufrufbares Objekt sein, das die folgenden Argumente entgegennimmt
errorhandler(connection, cursor, errorclass, errorvalue)
wobei connection eine Referenz auf die Verbindung ist, auf der der Cursor operiert, cursor eine Referenz auf den Cursor (oder
Noneim Falle, dass der Fehler nicht auf einen Cursor zutrifft), errorclass eine Fehlerklasse ist, die mit errorvalue als Konstruktorargument instanziiert werden soll.Der Standard-Fehlerbehandler sollte die Fehlerinformationen zum entsprechenden
.messages-Attribut (Connection.messages oder Cursor.messages) hinzufügen und die durch die gegebenen Parameter errorclass und errorvalue definierte Ausnahme auslösen.Wenn kein
.errorhandlergesetzt ist (das Attribut istNone), sollte das oben beschriebene Standard-Fehlerbehandlungsverfahren angewendet werden.Warnmeldung: „DB-API-Erweiterung .errorhandler verwendet“
Cursor sollten die Einstellung .errorhandler von ihren Verbindungsobjekten zum Zeitpunkt der Cursor-Erstellung erben.
Optionale Two-Phase Commit Erweiterungen
Viele Datenbanken unterstützen Two-Phase Commit (TPC), was die Verwaltung von Transaktionen über mehrere Datenbankverbindungen und andere Ressourcen hinweg ermöglicht.
Wenn ein Datenbank-Backend TPC unterstützt und der Autor des Datenbankmoduls diese Unterstützung offenlegen möchte, sollte die folgende API implementiert werden. NotSupportedError sollte ausgelöst werden, wenn die Unterstützung des Datenbank-Backends für TPC erst zur Laufzeit geprüft werden kann.
TPC Transaktions-IDs
Da viele Datenbanken der XA-Spezifikation folgen, bestehen Transaktions-IDs aus drei Komponenten
- eine Format-ID
- eine globale Transaktions-ID
- ein Branch-Qualifier
Für eine bestimmte globale Transaktion sollten die ersten beiden Komponenten für alle Ressourcen gleich sein. Jede Ressource in der globalen Transaktion sollte einen anderen Branch-Qualifier erhalten.
Die verschiedenen Komponenten müssen folgende Kriterien erfüllen
- Format-ID: eine nicht-negative 32-Bit-Ganzzahl.
- Globale Transaktions-ID und Branch-Qualifier: Byte-Strings nicht länger als 64 Zeichen.
Transaktions-IDs werden mit der Connection-Methode .xid() erstellt.
- .xid(format_id, global_transaction_id, branch_qualifier)
- Gibt ein Transaktions-ID-Objekt zurück, das für die Übergabe an die .tpc_*()-Methoden dieser Verbindung geeignet ist.
Wenn die Datenbankverbindung TPC nicht unterstützt, wird eine NotSupportedError ausgelöst.
Der Typ des von .xid() zurückgegebenen Objekts ist nicht definiert, aber es muss Sequenzverhalten aufweisen und den Zugriff auf die drei Komponenten ermöglichen. Ein konformes Datenbankmodul könnte Transaktions-IDs anstelle eines benutzerdefinierten Objekts mit Tupeln darstellen.
TPC Connection-Methoden
- .tpc_begin(xid)
- Beginnt eine TPC-Transaktion mit der gegebenen Transaktions-ID xid.
Diese Methode sollte außerhalb einer Transaktion aufgerufen werden (d.h. seit dem letzten .commit() oder .rollback() darf nichts ausgeführt worden sein).
Darüber hinaus ist es ein Fehler, .commit() oder .rollback() innerhalb der TPC-Transaktion aufzurufen. Eine ProgrammingError wird ausgelöst, wenn die Anwendung .commit() oder .rollback() während einer aktiven TPC-Transaktion aufruft.
Wenn die Datenbankverbindung TPC nicht unterstützt, wird eine NotSupportedError ausgelöst.
- .tpc_prepare()
- Führt die erste Phase einer mit .tpc_begin() gestarteten Transaktion aus. Eine ProgrammingError sollte ausgelöst werden, wenn diese Methode außerhalb einer TPC-Transaktion aufgerufen wird.
Nach dem Aufruf von .tpc_prepare() können keine Anweisungen mehr ausgeführt werden, bis .tpc_commit() oder .tpc_rollback() aufgerufen wurden.
- .tpc_commit([ xid ])
- Wenn ohne Argumente aufgerufen, committet .tpc_commit() eine zuvor mit .tpc_prepare() vorbereitete TPC-Transaktion.
Wenn .tpc_commit() vor .tpc_prepare() aufgerufen wird, wird ein Single-Phase-Commit durchgeführt. Ein Transaktionsmanager kann dies tun, wenn nur eine einzige Ressource an der globalen Transaktion beteiligt ist.
Wenn mit einer Transaktions-ID xid aufgerufen, committet die Datenbank die gegebene Transaktion. Wenn eine ungültige Transaktions-ID angegeben wird, wird eine ProgrammingError ausgelöst. Diese Form sollte außerhalb einer Transaktion aufgerufen werden und ist für die Wiederherstellung gedacht.
Nach der Rückkehr ist die TPC-Transaktion beendet.
- .tpc_rollback([ xid ])
- Wenn ohne Argumente aufgerufen, rollt .tpc_rollback() eine TPC-Transaktion zurück. Es kann vor oder nach .tpc_prepare() aufgerufen werden.
Wenn mit einer Transaktions-ID xid aufgerufen, rollt es die gegebene Transaktion zurück. Wenn eine ungültige Transaktions-ID angegeben wird, wird eine ProgrammingError ausgelöst. Diese Form sollte außerhalb einer Transaktion aufgerufen werden und ist für die Wiederherstellung gedacht.
Nach der Rückkehr ist die TPC-Transaktion beendet.
- .tpc_recover()
- Gibt eine Liste ausstehender Transaktions-IDs zurück, die mit
.tpc_commit(xid)oder.tpc_rollback(xid)verwendet werden können.Wenn die Datenbank keine Transaktionswiederherstellung unterstützt, kann sie eine leere Liste zurückgeben oder NotSupportedError auslösen.
Häufig gestellte Fragen
Die Datenbank-SIG sieht häufig wiederkehrende Fragen zur DB-API-Spezifikation. Dieser Abschnitt behandelt einige der Probleme, die Leute manchmal mit der Spezifikation haben.
Frage
Wie kann ich aus den von .fetch*() zurückgegebenen Tupeln ein Dictionary erstellen?
Antwort
Es gibt mehrere existierende Tools, die Helfer für diese Aufgabe bereitstellen. Die meisten davon verwenden den Ansatz, die Spaltennamen aus dem Cursor-Attribut .description als Grundlage für die Schlüssel im Zeilen-Dictionary zu verwenden.
Beachten Sie, dass der Grund für die Nicht-Erweiterung der DB-API-Spezifikation um die Unterstützung von Dictionary-Rückgabewerten für die Methoden .fetch*() darin liegt, dass dieser Ansatz mehrere Nachteile hat
- Einige Datenbanken unterstützen keine case-sensitiven Spaltennamen oder wandeln sie automatisch in Klein- oder Großbuchstaben um.
- Spalten im Ergebnisdatensatz, die durch die Abfrage generiert werden (z. B. durch die Verwendung von SQL-Funktionen), entsprechen keinen Tabellenspaltennamen, und Datenbanken generieren für diese Spalten normalerweise auf sehr datenbankspezifische Weise Namen.
Dadurch variiert der Zugriff auf die Spalten über Dictionary-Schlüssel zwischen Datenbanken und macht das Schreiben portablen Codes unmöglich.
Wesentliche Änderungen von Version 1.0 auf Version 2.0
Die Python Database API 2.0 führt im Vergleich zur Version 1.0 einige wichtige Änderungen ein. Da einige dieser Änderungen bestehende DB API 1.0-basierte Skripte brechen werden, wurde die Hauptversionsnummer angepasst, um diese Änderung widerzuspiegeln.
Dies sind die wichtigsten Änderungen von 1.0 auf 2.0
- Die Notwendigkeit eines separaten dbi-Moduls wurde gestrichen und die Funktionalität in die Modulschnittstelle selbst integriert.
- Neue Konstruktoren und Type Objects wurden für Datums-/Zeitwerte hinzugefügt, das
RAWType Object wurde inBINARYumbenannt. Der resultierende Satz sollte alle grundlegenden Datentypen abdecken, die üblicherweise in modernen SQL-Datenbanken vorkommen. - Neue Konstanten (apilevel, threadsafety, paramstyle) und Methoden (.executemany(), .nextset()) wurden hinzugefügt, um bessere Datenbankbindungen zu ermöglichen.
- Die Semantik von .callproc() zum Aufruf gespeicherter Prozeduren ist nun klar definiert.
- Die Definition des Rückgabewerts von .execute() wurde geändert. Zuvor basierte der Rückgabewert auf dem SQL-Anweisungstyp (was schwer richtig zu implementieren war) – er ist nun undefiniert; verwenden Sie stattdessen das flexiblere Attribut .rowcount. Module können die alten Rückgabewerte zurückgeben, aber diese sind nicht mehr zwingend durch die Spezifikation vorgeschrieben und sollten als datenbankschnittstellenabhängig betrachtet werden.
- Klassenbasierte Ausnahmen wurden in die Spezifikation aufgenommen. Modulimplementierer können das in dieser Spezifikation definierte Ausnahme-Layout erweitern, indem sie die definierten Ausnahmeklassen ableiten.
Ergänzungen zur DB API 2.0-Spezifikation nach der Veröffentlichung
- Zusätzliche optionale DB-API-Erweiterungen zum Satz der Kernfunktionalität wurden spezifiziert.
Offene Fragen
Obwohl die Spezifikation Version 2.0 viele Fragen klärt, die in Version 1.0 offen geblieben waren, gibt es noch einige offene Punkte, die in zukünftigen Versionen angegangen werden sollten.
- Definieren Sie einen nützlichen Rückgabewert für .nextset() für den Fall, dass ein neuer Ergebnissatz verfügbar ist.
- Integrieren Sie das
Decimal-Objekt aus dem decimal-Modul zur Verwendung als verlustfreie monetäre und dezimale Austauschformat.
Fußnoten
Danksagungen
Vielen Dank an Andrew Kuchling, der die Python Database API Specification 2.0 im Jahr 2001 aus dem ursprünglichen HTML-Format in das PEP-Format konvertierte.
Vielen Dank an James Henstridge für die Leitung der Diskussion, die 2008 zur Standardisierung der Two-Phase Commit API-Erweiterungen führte.
Vielen Dank an Daniele Varrazzo für die Konvertierung der Spezifikation vom Text-PEP-Format in das ReST-PEP-Format, das 2012 Links zu verschiedenen Teilen ermöglicht.
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0249.rst
Zuletzt geändert: 2025-02-01 08:55:40 GMT