一般捕获 python DatabaseErrors

Catch python DatabaseErrors generically

我有一个数据库模式,可以在各种不同的数据库引擎中实现(假设我将使用 pyodbc 连接到一个 MS Access 数据库,或者我将通过内置连接到一个 SQLite 数据库-在 sqlite3 模块中作为一个简单的例子)。

我想创建一个工厂function/method,returns 一个基于某些参数的适当类型的数据库连接,类似于以下内容:

def createConnection(connType, params):
    if connType == 'sqlite':
        return sqlite3.connect(params['filename'])
    elif connType == 'msaccess':
        return pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};DBQ={};'.format(params['filename']))
    else:
        # do something else

现在我有一些查询代码应该适用于任何连接类型(因为无论底层数据库引擎如何,模式都是相同的)但可能会抛出一个我需要捕获的异常:

db = createDatabase(params['dbType'], params)

cursor = db.cursor()

try:
    cursor.execute('SELECT A, B, C FROM TABLE')
    for row in cursor:
        print('{},{},{}'.format(row.A, row.B, row.C))

except DatabaseError as err:
    # Do something...

我遇到的问题是来自每个 DB API 2.0 实现的 DatabaseError classes 不共享一个公共基础 class(除了 way-too -generic Exception),所以我不知道如何一般地捕获这些异常。显然我可以做类似下面的事情:

try:
    # as before
except sqlite3.DatabaseError as err:
    # do something
except pyodbc.DatabaseError as err:
    # do something again

...我为每个可能的数据库引擎包含了一个显式的 catch 块。但这对我来说显然是非 pythonic 的。

如何从不同的底层数据库 API 2.0 数据库实现中捕获 DatabaseErrors?

有多种方法:

  1. 使用包罗万象的异常,然后找出它是什么异常。如果它不在您的列表中,请再次提出异常(或您自己的)。参见:Python When I catch an exception, how do I get the type, file, and line number?

  2. 也许您想以不同的方式解决问题:您的工厂代码还应该提供要测试的异常。

  3. 我认为(也是我在实践中使用的一种)更简单的方法是为所有数据库连接设置一个 class,然后将其子class每个特定的数据库 type/syntax。继承使您可以处理所有特殊性。出于某种原因,我从来不用担心这个问题。