自动打开和关闭数据库连接
我正在为我的应用程序编写一个用于数据库查询的类,使用的是SQLite3。这个类的大部分方法都很相似,像这样:
def getPrice(self, symbol, date):
date = dt.datetime.strptime(date, '%Y-%m-%d')
conn = sqlite3.connect('stocks.db')
curs =conn.cursor()
curs.execute('''SELECT close FROM prices WHERE symbol = ? AND date = ?;''', (symbol, date))
close = curs.fetchall()
curs.close()
return close
唯一的区别就是数据库查询的内容和参数的数量。有没有办法把打开和关闭数据库连接的过程简化一下呢?
我知道使用像SQLAlchemy这样的ORM可能会更简单。但我想了解的是,如何一般性地解决这类问题,而不仅仅是针对数据库。
谢谢你的建议!
编辑:这篇帖子基本上回答了我的问题。
3 个回答
把这些逻辑封装成一个对象,然后把这个对象传给数据访问对象,让它去调用相应的方法。
使用方面或装饰器可能是个不错的选择。
你没有提到连接池或事务,记得也要考虑这些内容。
注意,从Python 2.6开始,sqlite.connect
返回一个上下文管理器:
连接对象可以作为上下文管理器使用,这样可以自动处理事务的提交或回滚。如果出现异常,事务会被回滚;如果没有异常,事务会被提交:
所以,不要用contextlib.closing
来装饰连接——否则你会失去提交/回滚的功能,退出with语句
时只会调用connection.close()
。
根据PEP249:
... closing a connection without committing the changes first will cause
an implicit rollback to be performed.
所以,提交/回滚的功能比单纯调用关闭要有用得多。
你可以使用上下文管理器:
import contextlib
def query(sql,args):
with contextlib.closing(sqlite3.connect('stocks.db')) as conn:
curs = conn.cursor()
curs.execute(sql,args))
close = curs.fetchall()
return close
def getPrice(self, symbol, date):
date = dt.datetime.strptime(date, '%Y-%m-%d')
sql = '''SELECT close FROM prices WHERE symbol = ? AND date = ?'''
args = (symbol, date)
return query(sql, args)
由于你有很多像getPrice
这样的函数,它们只在SQL和参数上有所不同,你可以通过定义query
函数来减少重复的样板代码。
你还可以定义一个上下文管理器,在出现错误时回滚连接,并在退出with块时提交和关闭。关于这个(针对MySQL)的示例可以在这里找到,适配到sqlite3应该不难。
参考:
首先,只有一个全局连接会让你开心得多。这样配置的改变只需要在一个地方进行,简单方便。
其次,使用 with
语句和上下文管理器库。
from contextlib import closing
from my_database_module import the_global_connection
def getPrice(
with closing(the_global_connection.cursor())
curs.execute('''SELECT close FROM prices WHERE symbol = ? AND date = ?;''', (symbol, date))
close = curs.fetchall()
return close
你的数据库模块看起来是这样的:
import sqlite3
the_global_connection = sqlite3.connect( "stocks.db" )
这样你就可以在一个地方轻松地更换数据库或数据库服务器技术。