Namun, jika tidak dapat terhubung, maka
db
tidak akan ada lebih jauh - itulah sebabnya saya menetapkandb = None
di atas. Namun, apakah itu praktik yang baik?
Tidak, setel db = None
bukanlah praktik terbaik. Ada dua kemungkinan, menghubungkan ke database akan berhasil atau tidak.
-
Menghubungkan ke database tidak berfungsi:
Karena pengecualian yang dimunculkan telah ditangkap dan tidak dimunculkan kembali, Anda melanjutkan hingga mencapai
cursor = db.Cursor()
.db == None
, jadi, pengecualian yang menyerupaiTypeError: 'NoneType' object has no attribute 'Cursor'
akan dibangkitkan. Karena pengecualian yang dihasilkan saat koneksi database gagal telah diketahui, alasan kegagalan tersebut disamarkan.Secara pribadi, saya selalu mengajukan pengecualian koneksi kecuali Anda akan mencoba lagi segera. Bagaimana Anda menangkapnya terserah Anda; jika kesalahan berlanjut, saya mengirim email untuk mengatakan "pergi dan periksa database".
-
Menghubungkan ke database berfungsi:
Variabel
db
ditugaskan ditry:... except
memblokir. Jikaconnect
metode tidak berfungsi makadb
diganti dengan objek koneksi.
Bagaimanapun nilai awal db
tidak pernah digunakan.
Namun, saya pernah mendengar bahwa menggunakan penanganan pengecualian untuk kontrol aliran seperti ini adalah praktik yang buruk.
Tidak seperti bahasa lain Python tidak gunakan penanganan pengecualian untuk kontrol aliran. Di akhir jawaban saya, saya telah menautkan ke beberapa pertanyaan tentang Stack Overflow dan Programmer yang menanyakan pertanyaan serupa. Dalam setiap contoh Anda akan melihat kata-kata "tetapi dengan Python".
Itu tidak berarti bahwa Anda harus berlebihan tetapi Python umumnya menggunakan mantra EAFP, "Lebih mudah meminta maaf daripada meminta izin." Tiga contoh terpilih teratas di Bagaimana cara memeriksa apakah ada variabel? adalah contoh yang baik tentang bagaimana Anda berdua dapat menggunakan kontrol aliran atau tidak.
Apakah pengecualian bersarang adalah ide yang bagus? Atau adakah cara yang lebih baik untuk menangani pengecualian dependen/berjenjang seperti ini?
Tidak ada yang salah dengan pengecualian bersarang, sekali lagi selama Anda melakukannya dengan waras. Pertimbangkan kode Anda. Anda dapat menghapus semua pengecualian dan membungkus semuanya dalam try:... except
memblokir. Jika pengecualian dimunculkan maka Anda tahu apa itu, tetapi sedikit lebih sulit untuk melacak dengan tepat apa yang salah.
Lalu apa yang terjadi jika Anda ingin mengirim email kepada diri sendiri tentang kegagalan cursor.execute
? Anda harus memiliki pengecualian di sekitar cursor.execute
untuk melakukan tugas yang satu ini. Anda kemudian menaikkan kembali pengecualian sehingga tertangkap di try:...
. Tidak menaikkan ulang akan mengakibatkan kode Anda berlanjut seolah-olah tidak ada yang terjadi dan logika apa pun yang Anda masukkan ke dalam try:...
luar Anda untuk menangani pengecualian akan diabaikan.
Pada akhirnya semua pengecualian diwarisi dari BaseException
.
Juga, ada beberapa bagian (mis., kegagalan koneksi) di mana saya ingin skrip dihentikan saja - oleh karena itu panggilan sys.exit() yang dikomentari.
Saya telah menambahkan kelas sederhana dan bagaimana menyebutnya, yang kira-kira bagaimana saya akan melakukan apa yang Anda coba lakukan. Jika ini akan dijalankan di latar belakang maka pencetakan kesalahan tidak berguna - orang tidak akan duduk di sana secara manual mencari kesalahan. Mereka harus masuk apa pun cara standar Anda dan orang yang tepat diberi tahu. Saya telah menghapus pencetakan karena alasan ini dan menggantinya dengan pengingat untuk masuk.
Karena saya telah membagi kelas menjadi beberapa fungsi ketika connect
metode gagal dan pengecualian muncul execute
panggilan tidak akan dijalankan dan skrip akan selesai, setelah mencoba memutuskan sambungan.
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()
Kemudian sebut saja:
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()
Bacaan lebih lanjut:
cx_Oracle
dokumentasi
Mengapa tidak menggunakan pengecualian sebagai aliran kontrol reguler?
Apakah penanganan pengecualian python lebih efisien daripada PHP dan/atau bahasa lain?
Argumen mendukung atau menentang penggunaan try catch sebagai operator logika