但是,如果它无法连接,那么db 将不存在进一步向下 -
这就是我在上面设置db = None 的原因。但是,这是好的做法吗?
不,设置db = None 不是最佳做法。有两种可能,要么连接到数据库,要么不连接。
-
连接数据库不起作用:
由于引发的异常已被捕获且未重新引发,因此您将继续操作,直到到达 cursor = db.Cursor()。
db == None,因此,将引发类似于TypeError: 'NoneType' object has no attribute 'Cursor' 的异常。由于数据库连接失败时产生的异常已经被捕获,所以失败的原因是伪装的。
就个人而言,除非您很快再试一次,否则我总是会引发连接异常。如何捕捉它取决于你;如果错误仍然存在,我会通过电子邮件说“去检查数据库”。
-
连接到数据库确实有效:
变量db 分配在您的try:... except 块中。如果connect 方法确实有效,则db 将替换为连接对象。
无论哪种方式,db 的初始值都不会被使用。
但是,我听说使用异常处理来进行流控制
这样是不好的做法。
与其他语言不同,Python 确实使用异常处理来进行流控制。在我的回答结束时,我已经链接到 Stack Overflow 和 Programmers 上提出类似问题的几个问题。在每个示例中,您都会看到“但在 Python 中”的字样。
这并不是说你应该过分,但 Python 通常使用 EAFP 的口头禅,“请求宽恕比请求许可更容易。” How do I check if a variable exists? 中投票的前三名示例很好关于如何使用流量控制的示例。
嵌套异常是个好主意吗?或者有没有更好的处理方式
有这样的依赖/级联异常?
嵌套异常并没有什么问题,只要您理智地执行此操作即可。考虑你的代码。您可以删除所有异常并将整个事物包装在 try:... except 块中。如果引发了异常,那么您就会知道它是什么,但是要准确找出问题所在就有点困难了。
如果您想在cursor.execute 失败时向自己发送电子邮件,会发生什么情况?您应该在cursor.execute 周围有一个例外,以便执行这项任务。然后,您重新引发异常,使其被您的外部try:... 捕获。不重新引发将导致您的代码继续运行,就好像什么都没发生一样,并且您在外部 try:... 中放置的用于处理异常的任何逻辑都将被忽略。
最终所有的异常都继承自BaseException。
另外,还有一些我想要的部分(例如连接失败)
脚本只是终止 - 因此注释掉 sys.exit() 调用。
我添加了一个简单的类以及如何调用它,这大致就是我将如何做你想做的事情。如果这要在后台运行,那么打印错误是不值得的——人们不会坐在那里手动寻找错误。他们应该以您的标准方式登录,并通知适当的人。出于这个原因,我删除了打印并替换为记录提醒。
当connect 方法失败并引发异常时,我已将类拆分为多个函数,因此在尝试断开连接后,execute 调用将不会运行并且脚本将完成。
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()
然后调用它:
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()
延伸阅读:
cx_Oracle documentation
Why not use exceptions as regular flow of control?
Is python exception handling more efficient than PHP and/or other languages?
Arguments for or against using try catch as logical operators