Tuy nhiên, nếu nó không thể kết nối, thì
db
sẽ không tồn tại nữa - đó là lý do tại sao tôi đặtdb = None
bên trên. Tuy nhiên, đó có phải là cách làm tốt không?
Không, cài đặt db = None
không phải là phương pháp hay nhất. Có hai khả năng, hoặc kết nối với cơ sở dữ liệu sẽ hoạt động hoặc không.
-
Kết nối với cơ sở dữ liệu không hoạt động:
Vì ngoại lệ đã nêu ra đã bị bắt và không được nâng lên, bạn tiếp tục cho đến khi bạn đến
cursor = db.Cursor()
.db == None
, do đó, một ngoại lệ giống vớiTypeError: 'NoneType' object has no attribute 'Cursor'
sẽ được nâng lên. Vì trường hợp ngoại lệ được tạo ra khi kết nối cơ sở dữ liệu không thành công đã được bắt, nên lý do của sự cố được ngụy tạo.Cá nhân tôi luôn nêu ra một ngoại lệ kết nối trừ khi bạn định thử lại trong thời gian ngắn. Bạn nắm bắt nó như thế nào là tùy thuộc vào bạn; nếu lỗi vẫn tiếp diễn, tôi gửi e-mail thông báo "hãy đi và kiểm tra cơ sở dữ liệu".
-
Kết nối với cơ sở dữ liệu hoạt động:
Biến
db
được chỉ định trongtry:... except
khối. Nếuconnect
phương thức không hoạt động sau đódb
được thay thế bằng đối tượng kết nối.
Dù bằng cách nào thì giá trị ban đầu của db
không bao giờ được sử dụng.
Tuy nhiên, tôi đã nghe nói rằng việc sử dụng xử lý ngoại lệ cho điều khiển luồng, đây là một phương pháp không tốt.
Không giống như các ngôn ngữ khác, Python does sử dụng xử lý ngoại lệ để kiểm soát luồng. Ở cuối câu trả lời của mình, tôi đã liên kết đến một số câu hỏi trên Stack Overflow và Lập trình viên hỏi một câu hỏi tương tự. Trong mọi ví dụ, bạn sẽ thấy các từ "nhưng bằng Python".
Điều đó không có nghĩa là bạn nên làm quá đà nhưng Python thường sử dụng câu thần chú EAFP, "Xin sự tha thứ thì dễ hơn là xin phép". Ba ví dụ được bình chọn hàng đầu trong Làm cách nào để kiểm tra xem một biến có tồn tại hay không? là những ví dụ điển hình về cách bạn có thể sử dụng cả điều khiển luồng hay không.
Các trường hợp ngoại lệ lồng vào nhau có phải là một ý kiến hay không? Hay có cách nào tốt hơn để xử lý với các trường hợp ngoại lệ phụ thuộc / xếp tầng như thế này?
Không có gì sai với các ngoại lệ lồng nhau, một lần nữa, miễn là bạn làm điều đó một cách lành mạnh. Xem xét mã của bạn. Bạn có thể loại bỏ tất cả các ngoại lệ và gói toàn bộ trong một try:... except
khối. Nếu một ngoại lệ được đưa ra thì bạn biết đó là gì, nhưng sẽ khó hơn một chút để tìm ra chính xác điều gì đã xảy ra.
Điều gì xảy ra sau đó nếu bạn muốn tự mình gửi e-mail về lỗi cursor.execute
? Bạn nên có một ngoại lệ xung quanh cursor.execute
để thực hiện một nhiệm vụ này. Sau đó, bạn nâng lại ngoại lệ để nó bị mắc vào try:...
. Việc không nâng cấp lại sẽ dẫn đến việc mã của bạn tiếp tục như thể không có gì xảy ra và bất kỳ logic nào bạn đã đưa vào try:...
để đối phó với một ngoại lệ sẽ bị bỏ qua.
Cuối cùng thì tất cả các ngoại lệ đều được kế thừa từ BaseException
.
Ngoài ra, có một số phần (ví dụ:lỗi kết nối) mà tôi muốn tập lệnh chỉ kết thúc - do đó lệnh gọi sys.exit () đã nhận xét.
Tôi đã thêm một lớp đơn giản và cách gọi nó, đại khái là cách tôi thực hiện những gì bạn đang cố gắng làm. Nếu điều này sẽ được chạy ở chế độ nền thì việc in ra các lỗi không đáng giá - mọi người sẽ không ngồi đó để tìm lỗi theo cách thủ công. Họ phải được đăng nhập bằng bất kỳ cách tiêu chuẩn nào của bạn và những người thích hợp được thông báo. Tôi đã xóa bản in vì lý do này và thay thế bằng lời nhắc ghi nhật ký.
Vì tôi đã chia lớp thành nhiều chức năng khi connect
phương thức không thành công và một ngoại lệ được đưa ra execute
cuộc gọi sẽ không được chạy và tập lệnh sẽ kết thúc sau khi cố gắng ngắt kết nối.
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()
Sau đó gọi nó là:
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()
Đọc thêm:
cx_Oracle
tài liệu
Tại sao không sử dụng ngoại lệ làm luồng kiểm soát thông thường?
Việc xử lý ngoại lệ trong python có hiệu quả hơn PHP và / hoặc các ngôn ngữ khác không?
Lập luận ủng hộ hoặc phản đối việc sử dụng try catch làm toán tử logic