However, if it can’t connect, then db won’t exist further down –
which is why I set db = None above. However, is that good practice?
不,设置db = None不是最佳做法。有两种可能性,连接到数据库将工作或不会。
>连接到数据库不起作用:
由于引发的异常已被捕获,并且不会被重新引导,您将继续,直到到达cursor = db.Cursor()。
db == None,所以,类似于TypeError的异常:’NoneType’对象没有属性’Cursor’将被提出。当数据库连接失败时生成的异常已被捕获,故障原因被伪装。
就个人而言,我总是提出一个连接异常,除非你稍后再试一次。你如何抓住它取决于你;如果错误仍然存在,我通过电子邮件来说“去查看数据库”。
>连接到数据库确实有效:
变量db在您的try中分配:… except block。如果connect方法工作,那么db将替换为连接对象。
无论哪种方式,db的初始值都不会被使用。
However, I’ve heard that using exception handling for flow control
like this is bad practice.
与其他语言不同,Python对流控制使用异常处理。在我的答案的最后,我已经链接到堆栈溢出和程序员的几个问题,提出类似的问题。在每个例子中,你会看到“但是在Python”这个词。
这并不是说你应该过分笨拙,但Python通常会使用咒语EAFP:“要求宽恕而不是许可要容易得多”。 How do I check if a variable exists?中排名前三的投票例子是如何使用流量控制的好例子。
Is nesting exceptions a good idea? Or is there a better way of dealing
with dependent/cascaded exceptions like this?
嵌套异常没有任何问题,只要你做得很好,就再一次。考虑你的代码您可以删除所有异常并将整个事情包装在一起:…除了块。如果一个例外被提出,那么你知道它是什么,但是更准确地追踪到底是什么问题。
如果你想在光标失败的情况下自己发电子邮件发生什么呢?为了执行这个任务,你应该在cursor.execute周围有一个异常。然后,您可以重新提出异常,以便在外部尝试中被捕获:….不重新提升会导致您的代码继续,就像没有发生任何事情一样,以及您外部尝试的任何逻辑:…处理有一个例外将被忽略。
Also, there are some parts (e.g. connection failures) where I’d like
the script to just terminate – hence the commented out sys.exit() call.
我添加了一个简单的类和如何调用它,这大概是我将如何做你想做的事情;我已经“偷走”你的代码的打印部分来做到这一点。如果这将在后台运行,则错误的打印是不值得的。我实际上将它们记录到数据库中,如果数据库由于任何原因而不可用,则发送电子邮件。
由于在连接方法失败并引发异常时,我将该类分成多个函数,因此在尝试断开连接后,执行调用将不会运行,并且脚本将完成。
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:
error, = e.args
if error.code == 1017:
print('Please check your credentials.')
else:
print('Database connection error: %s'.format(e))
# Very important part!
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 we don't really care.
"""
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:
error, = e.args
if error.code == 955:
print('Table already exists')
elif error.code == 1031:
print("Insufficient privileges")
print(error.code)
print(error.message)
print(error.context)
# Raise the exception.
raise
# Only commit if it-s necessary.
if commit:
self.db.commit()
然后叫它:
if __name__ == "__main__":
try:
oracle = Oracle.connect('username', 'password', 'hostname'
, 'port', 'servicename')
# 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()
进一步阅读: