Wenn es jedoch keine Verbindung herstellen kann, dann db
wird weiter unten nicht mehr existieren - weshalb ich db = None
gesetzt habe Oben. Ist das jedoch eine bewährte Vorgehensweise?
Nein, Einstellung db = None
ist nicht die beste Praxis. Es gibt zwei Möglichkeiten, entweder funktioniert die Verbindung zur Datenbank oder nicht.
-
Die Verbindung zur Datenbank funktioniert nicht:
Da die ausgelöste Ausnahme abgefangen und nicht erneut ausgelöst wurde, fahren Sie fort, bis Sie
cursor = db.Cursor()
erreichen .db == None
, also eine Ausnahme, dieTypeError: 'NoneType' object has no attribute 'Cursor'
ähnelt wird erhoben. Da die beim Fehlschlagen der Datenbankverbindung generierte Ausnahme bereits abgefangen wurde, wird der Grund für den Fehler verschleiert.Persönlich würde ich immer eine Verbindungsausnahme auslösen, es sei denn, Sie versuchen es in Kürze erneut. Wie Sie es fangen, liegt an Ihnen; Wenn der Fehler weiterhin besteht, sende ich eine E-Mail mit der Aufschrift "Gehen Sie und überprüfen Sie die Datenbank".
-
Die Verbindung zur Datenbank funktioniert:
Die Variable
db
in Ihremtry:... except
zugewiesen ist Block. Wenn derconnect
Methode funktioniert danndb
wird durch das Verbindungsobjekt ersetzt.
So oder so der Anfangswert von db
wird nie verwendet.
Ich habe jedoch gehört, dass die Verwendung einer Ausnahmebehandlung für die Flusskontrolle wie diese eine schlechte Praxis ist.
Im Gegensatz zu anderen Sprachen macht es Python Verwenden Sie die Ausnahmebehandlung für die Flusssteuerung. Am Ende meiner Antwort habe ich mehrere Fragen zu Stack Overflow und Programmierern verlinkt, die eine ähnliche Frage stellen. In jedem Beispiel sehen Sie die Worte "but in Python".
Das soll nicht heißen, dass Sie es übertreiben sollten, aber Python verwendet im Allgemeinen das Mantra EAFP, "Es ist einfacher, um Vergebung als um Erlaubnis zu bitten." Die drei am besten bewerteten Beispiele in Wie überprüfe ich, ob eine Variable existiert? sind gute Beispiele dafür, wie Sie sowohl die Flusskontrolle verwenden können als auch nicht.
Ist das Verschachteln von Ausnahmen eine gute Idee? Oder gibt es eine bessere Möglichkeit, mit abhängigen/kaskadierten Ausnahmen wie dieser umzugehen?
An verschachtelten Ausnahmen ist nichts auszusetzen, solange Sie es vernünftig tun. Betrachten Sie Ihren Code. Sie könnten alle Ausnahmen entfernen und das Ganze in einen try:... except
einpacken Block. Wenn eine Ausnahme ausgelöst wird, wissen Sie, was es war, aber es ist etwas schwieriger, genau herauszufinden, was schief gelaufen ist.
Was passiert dann, wenn Sie sich per E-Mail über den Fehler von cursor.execute
informieren möchten ? Sie sollten eine Ausnahme um cursor.execute
haben um diese eine Aufgabe zu erfüllen. Anschließend lösen Sie die Ausnahme erneut aus, sodass sie in Ihrem äußeren try:...
abgefangen wird . Nicht erneutes Erhöhen würde dazu führen, dass Ihr Code weitermacht, als ob nichts passiert wäre, und welche Logik Sie auch immer in Ihr äußeres try:...
eingefügt haben um eine Ausnahme zu behandeln, würde ignoriert.
Letztendlich werden alle Ausnahmen von BaseException
geerbt .
Außerdem gibt es einige Teile (z. B. Verbindungsfehler), bei denen ich möchte, dass das Skript einfach beendet wird - daher der auskommentierte Aufruf von sys.exit().
Ich habe eine einfache Klasse hinzugefügt und wie man sie nennt, was ungefähr so wäre, wie ich tun würde, was Sie versuchen zu tun. Wenn dies im Hintergrund laufen soll, lohnt sich das Drucken der Fehler nicht - die Leute sitzen nicht da und suchen manuell nach Fehlern. Sie sollten auf Ihrem üblichen Weg angemeldet und die entsprechenden Personen benachrichtigt werden. Ich habe den Aufdruck aus diesem Grund entfernt und durch eine Erinnerung zum Anmelden ersetzt.
Da ich die Klasse in mehrere Funktionen aufgeteilt habe, wenn der connect
Methode schlägt fehl und eine Ausnahme wird beim execute
ausgelöst Der Anruf wird nicht ausgeführt und das Skript wird beendet, nachdem versucht wurde, die Verbindung zu trennen.
import cx_Oracle
class Oracle(object):
def connect(self, username, password, hostname, port, servicename):
""" Connect to the database. """
try:
self.db = cx_Oracle.connect(username, password
, hostname + ':' + port + '/' + servicename)
except cx_Oracle.DatabaseError as e:
# Log error as appropriate
raise
# If the database connection succeeded create the cursor
# we-re going to use.
self.cursor = self.db.cursor()
def disconnect(self):
"""
Disconnect from the database. If this fails, for instance
if the connection instance doesn't exist, ignore the exception.
"""
try:
self.cursor.close()
self.db.close()
except cx_Oracle.DatabaseError:
pass
def execute(self, sql, bindvars=None, commit=False):
"""
Execute whatever SQL statements are passed to the method;
commit if specified. Do not specify fetchall() in here as
the SQL statement may not be a select.
bindvars is a dictionary of variables you pass to execute.
"""
try:
self.cursor.execute(sql, bindvars)
except cx_Oracle.DatabaseError as e:
# Log error as appropriate
raise
# Only commit if it-s necessary.
if commit:
self.db.commit()
Nennen Sie es dann:
if __name__ == "__main__":
oracle = Oracle.connect('username', 'password', 'hostname'
, 'port', 'servicename')
try:
# No commit as you don-t need to commit DDL.
oracle.execute('ddl_statements')
# Ensure that we always disconnect from the database to avoid
# ORA-00018: Maximum number of sessions exceeded.
finally:
oracle.disconnect()
Weiterführende Literatur:
cx_Oracle
Dokumentation
Warum nicht Ausnahmen als regulären Kontrollfluss verwenden?
Ist die Behandlung von Ausnahmen in Python effizienter als PHP und/oder andere Sprachen?
Argumente für oder gegen die Verwendung von try catch als logische Operatoren