我习惯(宠坏了?)python的SQLite接口来处理SQL数据库。 python的SQLite API中的一个很好的特性是“上下文管理器”,即python的with
语句。我通常以下列方式执行查询:
import as sqlite
with sqlite.connect(db_filename) as conn:
query = "INSERT OR IGNORE INTO shapes VALUES (?,?);"
results = conn.execute(query, ("ID1","triangle"))
使用上面的代码,如果我的查询修改了数据库而忘记运行conn.commit()
,则上下文管理器会在退出with
语句后自动为我运行它。它还可以很好地处理异常:如果在我提交任何内容之前发生异常,则回滚数据库。
我现在正在使用MySQLdb
界面,它似乎不支持开箱即用的类似上下文管理器。我如何创建自己的?有一个相关的问题here,但它没有提供完整的解决方案。
答案 0 :(得分:19)
Previously,MySQLdb连接是上下文管理器。 但是,从this commit on 2018-12-04开始,MySQLdb连接不再是上下文管理器, 用户必须显式调用conn.commit()或conn.rollback(),或者编写自己的上下文管理器,例如下面的那个。
您可以使用以下内容:
import config
import MySQLdb
import MySQLdb.cursors as mc
import _mysql_exceptions
import contextlib
DictCursor = mc.DictCursor
SSCursor = mc.SSCursor
SSDictCursor = mc.SSDictCursor
Cursor = mc.Cursor
@contextlib.contextmanager
def connection(cursorclass=Cursor,
host=config.HOST, user=config.USER,
passwd=config.PASS, dbname=config.MYDB,
driver=MySQLdb):
connection = driver.connect(
host=host, user=user, passwd=passwd, db=dbname,
cursorclass=cursorclass)
try:
yield connection
except Exception:
connection.rollback()
raise
else:
connection.commit()
finally:
connection.close()
@contextlib.contextmanager
def cursor(cursorclass=Cursor, host=config.HOST, user=config.USER,
passwd=config.PASS, dbname=config.MYDB):
with connection(cursorclass, host, user, passwd, dbname) as conn:
cursor = conn.cursor()
try:
yield cursor
finally:
cursor.close()
with cursor(SSDictCursor) as cur:
print(cur)
connection = cur.connection
print(connection)
sql = 'select * from table'
cur.execute(sql)
for row in cur:
print(row)
要使用它,您可以在PYTHONPATH中放置config.py
并在那里定义HOST,USER,PASS和MYDB变量。
答案 1 :(得分:18)
自从这个问题最初被问到以来,认为情况发生了变化。有点令人困惑(至少从我的观点来看),对于MySQLdb
的最新版本,如果在上下文中使用连接,则会得到一个游标(根据oursql
示例),而不是关闭的东西自动(就像你打开文件一样)。
这就是我的所作所为:
from contextlib import closing
with closing(getConnection()) as conn: #ensure that the connection is closed
with conn as cursor: #cursor will now auto-commit
cursor.execute('SELECT * FROM tablename')