如何确保 Python 中的数据库连接在离开代码块之前总是关闭

在 Python 中,如何确保在离开代码块之前数据库连接始终关闭?我们希望尽可能防止数据库连接保持打开状态,因为此代码将在密集使用服务器上运行,此处的人员已经告诉我们数据库连接应尽快关闭。

具体示例如下:

def do_something_that_needs_database():
    dbConnection = MySQLdb.connect(host=args['database_host'], user=args['database_user'], passwd=args['database_pass'], db=args['database_tabl'], cursorclass=MySQLdb.cursors.DictCursor)
    dbCursor = dbConnection.cursor()
    dbCursor.execute('SELECT COUNT(*) total FROM table')
    row = dbCursor.fetchone()
    if row['total'] == 0:
        print('error: table have no records')
        dbCursor.execute('UPDATE table SET field="%s"', whatever_value)
        return None
    print('table is ok')
    dbCursor.execute('UPDATE table SET field="%s"', another_value)

    # a lot more of workflow done here

    dbConnection.close()

    # even more stuff would come below

我们认为,当表中没有行时,该方法将使数据库连接保持打开状态,虽然我们仍不确定它是如何工作的。无论如何,从某种意义上说,这可能是一种糟糕的设计,因为可以在每个小执行块之后打开和关闭 DB 连接。当然,在这种情况下,我们可以在 return 之前添加一个 close。

2、解决方案

解决方案 1:使用 try/finally 语句

传统的方法是使用 try/finally 语句,如下所示:

def do_something_that_needs_database():
    dbConnection = MySQLdb.connect(host=args['database_host'], user=args['database_user'], passwd=args['database_pass'], db=args['database_tabl'], cursorclass=MySQLdb.cursors.DictCursor)
    try:
        # as much work as you want, including return, raising exceptions, _whatever_
    finally:
        closeDb(dbConnection)

解决方案 2:使用 with 语句

从 Python 2.6(以及 2.5 带有 from future import with_statement)开始,还有一种替代方法(尽管 try/finally 仍然非常有效!):with 语句。

with somecontext as whatever:
    # the work goes here

上下文具有一个 enter 方法,在进入时执行(如果需要,返回上述 whatever),还有一个 exit 方法,在退出时执行。尽管这种方法很优雅,但由于没有现成的上下文以您想要的方式工作,因此构建一个所需的工作(尽管在 2.6 中通过 contextlib 减少了)可能应该表明传统的 try/finally 最好。

如果您有 2.6 并想尝试 contextlib,则可以通过以下方式“隐藏”try/finally,如下所示:

import contextlib

@contextlib.contextmanager
def dbconnect(**kwds):
  dbConnection = MySQLdb.connect(**kwds)
  try:
    yield dbConnection
  finally:
    closeDb(dbConnection)

可用于如下所示:

def do_something_that_needs_database():
    with dbconnect(host=args['database_host'], user=args['database_user'],
                   passwd=args['database_pass'], db=args['database_tabl'],
                   cursorclass=MySQLdb.cursors.DictCursor) as dbConnection:
        # as much work as you want, including return, raising exceptions, _whatever_

如果要多次使用它,这可能值得这样做,只是为了避免针对这些多次使用反复重复 try/finally。

解决方案 3:使用 try/finally 块

def do_something_that_needs_database():
    dbConnection = MySQLdb.connect(host=args['database_host'], user=args['database_user'], passwd=args['database_pass'], db=args['database_tabl'], cursorclass=MySQLdb.cursors.DictCursor)
    try:
        # Do some processing
    finally:
        # Cleanup

解决方案 4:使用 contextlib 方法

假设您使用的 DB 驱动程序开箱即用不支持,请尝试使用 contextlib 中的 closing 方法。

猜你喜欢

转载自blog.csdn.net/D0126_/article/details/143115460