我想尽可能防止数据库连接被打开,因为这段代码将在密集使用的服务器上运行,这里的人已经告诉我应该尽快关闭数据库连接。
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
我相信当桌面上没有行时,会打开数据库连接,I'm still really not sure how it works。
无论如何,也许这是糟糕的设计,因为我可以在execute
的每个小块之后打开和关闭数据库连接。当然,我可以在close
之前添加一个return
...
但是,我怎么能总是正确地关闭数据库而不必担心我是否有return
,raise
或continue
,或者其他什么?我正在考虑像代码块一样,类似于使用try
,就像在下面的建议中一样,这显然不起作用:
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:
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)
# again, that same lot of line codes done here
except ExitingCodeBlock:
closeDb(dbConnection)
# still, that "even more stuff" from before would come below
我认为没有类似于ExitingCodeBlock
的异常,我知道有尝试 else
,但我希望Python已经有类似的特征...
也许有人可以建议我采取范式,并告诉我这很糟糕,并且高度建议我永远不要这样做。也许这只是不用担心的问题,让MySQLdb处理它,或者是它?
答案 0 :(得分:23)
传统方法是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)
自Python 2.6(以及带有from __future__ import with_statement
的2.5)以来,有一种替代方法(尽管try
/ finally
仍能正常运行!):with
语句。
with somecontext as whatever:
# the work goes here
上下文有__enter__
方法,在进入时执行(如果需要,返回上面的whatever
)和退出时执行的__exit__
方法。尽管优雅,但由于没有现有的上下文按照你想要的方式工作,所以构建一个所需的工作(虽然用contextlib
减少了2.6)应该可能表明好的旧尝试/最终是最好的。
如果你有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_
如果你打算多次使用它,可能是值得的,只是为了避免重复尝试/最后反复进行这些用途。
答案 1 :(得分:6)
如果MySQLdb支持它,那么你可以使用“with”语句。出于这个原因,存在“with”语句。但是,它要求对象定义__enter__和__exit__以使其起作用。
作为with语句的一个例子......对于读/写文件,你可能有:
with open('filename','r') as file:
for line in file:
# processing....
# File automatically closed afterwards or if there was an exception thrown
如果它不支持它,那么你总是可以使用try ... finally,如:
try:
# Do some processing
finally:
# Cleanup
无论try是如何完成的,都会执行finally子句(无论它是成功完成,还是传播但是被捕获,或者抛出异常并继续传播)。
答案 2 :(得分:4)
假设您使用的数据库驱动程序不支持with
开箱即用,请尝试the closing
method from contextlib
。
答案 3 :(得分:3)
为什么不把它包装成try:finally:block?
http://docs.python.org/tutorial/errors.html#defining-clean-up-actions
这就是最终阻止的目标。