在 Python 中跨多个函数使用 MySQLdb 连接和游标的正确方法是什么
What is the proper way of using MySQLdb connections and cursors across multiple functions in Python
我是 Python 及其 MySQLdb 连接器的新手。
我正在使用 RESTful 方法从数据库中将一些数据写入 API 到 return。在 PHP 中,我将连接管理部分包装在 class 中,充当 MySQL 查询的抽象层。
在Python中:
我在脚本的早期定义了连接: con = mdb.connect('localhost', 'user', 'passwd', 'dbname')
那么,在后续的所有方法中:
import MySQLdb as mdb
def insert_func():
with con:
cur = con.cursor(mdb.cursors.DictCursor)
cur.execute("INSERT INTO table (col1, col2, col3) VALUES (%s, %s, %s)", (val1, val2, val3) )
rows = cur.fetchall()
#do something with the results
return someval
等
我使用mdb.cursors.DictCursor
因为我更喜欢能够以关联数组的方式访问数据库列。
现在问题开始出现:
在一个函数中,我发出一个插入查询以创建具有唯一性 'groupid' 的 'group'。
这个 'group' 有一个创作者。数据库中的每个用户都在 table 的 his/her 行的 'groups' 列中持有一个 JSON 数组。
所以当我创建一个新组时,我想将groupid分配给创建它的用户。
我使用类似的功能更新用户的记录。
我将 'insert' 和 'update' 部分包装在两个单独的函数定义中。
我第一次运行脚本,一切正常。
我第二次 运行 脚本,脚本 运行 无休止地运行(我怀疑是由于与 MySQL 数据库的一些空闲连接)。
当我使用 CTRL + C 中断它时,出现以下错误之一:
- "'Cursor' 对象没有属性 'connection'"
- "commands out of sync; you can't run this command now"
- 或预期的任何其他 KeyboardInterrupt 异常。
在我看来,这些错误是由我的代码中处理连接和游标的某些错误方式引起的。
我读到使用 with con:
是一种很好的做法,这样连接将在查询后自动关闭。我在每个函数中对 'con' 使用 'with',因此连接已关闭,但我决定全局定义连接,以便任何函数使用它。这似乎与 with con:
上下文管理不兼容。我怀疑光标需要以类似的方式 'context managed',但我不知道该怎么做(据我所知,PHP 不使用 MySQL 的光标,所以我没有使用它们的经验)。
我现在有以下问题:
为什么第一次可以,第二次不行? (但是,在 CTRL + C 中断后,它会再次工作一次)。
在使用多个函数(可以按顺序调用)时,如何使用连接和游标?
我认为这里有两个主要问题 - 一个似乎是 python 代码,另一个是您与数据库交互的结构。
首先,您没有关闭连接。这取决于您的应用程序的需求——您必须决定它应该保持打开状态多长时间。参考文献this SO question
from contextlib import closing
with closing( connection.cursor() ) as cursor:
... use the cursor ...
# cursor closed. Guaranteed.
connection.close()
现在,您必须使用 Ctl+C
中断您的程序,因为您的 with
语句没有理由停止 运行。
其次,开始根据 'transactions' 考虑您与数据库的交互。做一些事情,将它提交给数据库,如果它不起作用,则回滚,如果它起作用,则关闭连接。 Here's a tutorial.
与连接一样,与文件句柄一样 rule of thumb is open late, close early.
所以我建议仅在他们尝试做一件事时共享连接。或者,如果您使用多进程,那么每个进程都会获得一个连接,同样遵循晚开、早关的原则。如果您正在进行顺序操作(比如在循环中),则在循环外打开和关闭。拥有全球连接可能会变得混乱。主要是因为现在你必须跟踪哪个函数在什么时候使用它,以及它试图用它做什么。
"cannot run command now" 的问题是因为您的键盘中断终止了活动连接。
关于你的问题的第一部分 - 无休止地可能在任何地方。 python 的每个实例都将获得自己的连接。因此,当您第二次 运行 它时,它应该获得自己的连接。打开一个 mysql 客户端并执行
show full processlist
看看发生了什么。
我是 Python 及其 MySQLdb 连接器的新手。 我正在使用 RESTful 方法从数据库中将一些数据写入 API 到 return。在 PHP 中,我将连接管理部分包装在 class 中,充当 MySQL 查询的抽象层。
在Python中:
我在脚本的早期定义了连接:
con = mdb.connect('localhost', 'user', 'passwd', 'dbname')
那么,在后续的所有方法中:
import MySQLdb as mdb def insert_func(): with con: cur = con.cursor(mdb.cursors.DictCursor) cur.execute("INSERT INTO table (col1, col2, col3) VALUES (%s, %s, %s)", (val1, val2, val3) ) rows = cur.fetchall() #do something with the results return someval
等
我使用
mdb.cursors.DictCursor
因为我更喜欢能够以关联数组的方式访问数据库列。
现在问题开始出现:
在一个函数中,我发出一个插入查询以创建具有唯一性 'groupid' 的 'group'。
这个 'group' 有一个创作者。数据库中的每个用户都在 table 的 his/her 行的 'groups' 列中持有一个 JSON 数组。
所以当我创建一个新组时,我想将groupid分配给创建它的用户。
我使用类似的功能更新用户的记录。
我将 'insert' 和 'update' 部分包装在两个单独的函数定义中。
我第一次运行脚本,一切正常。
我第二次 运行 脚本,脚本 运行 无休止地运行(我怀疑是由于与 MySQL 数据库的一些空闲连接)。
当我使用 CTRL + C 中断它时,出现以下错误之一:
- "'Cursor' 对象没有属性 'connection'"
- "commands out of sync; you can't run this command now"
- 或预期的任何其他 KeyboardInterrupt 异常。
在我看来,这些错误是由我的代码中处理连接和游标的某些错误方式引起的。
我读到使用 with con:
是一种很好的做法,这样连接将在查询后自动关闭。我在每个函数中对 'con' 使用 'with',因此连接已关闭,但我决定全局定义连接,以便任何函数使用它。这似乎与 with con:
上下文管理不兼容。我怀疑光标需要以类似的方式 'context managed',但我不知道该怎么做(据我所知,PHP 不使用 MySQL 的光标,所以我没有使用它们的经验)。
我现在有以下问题:
为什么第一次可以,第二次不行? (但是,在 CTRL + C 中断后,它会再次工作一次)。
在使用多个函数(可以按顺序调用)时,如何使用连接和游标?
我认为这里有两个主要问题 - 一个似乎是 python 代码,另一个是您与数据库交互的结构。
首先,您没有关闭连接。这取决于您的应用程序的需求——您必须决定它应该保持打开状态多长时间。参考文献this SO question
from contextlib import closing
with closing( connection.cursor() ) as cursor:
... use the cursor ...
# cursor closed. Guaranteed.
connection.close()
现在,您必须使用 Ctl+C
中断您的程序,因为您的 with
语句没有理由停止 运行。
其次,开始根据 'transactions' 考虑您与数据库的交互。做一些事情,将它提交给数据库,如果它不起作用,则回滚,如果它起作用,则关闭连接。 Here's a tutorial.
与连接一样,与文件句柄一样 rule of thumb is open late, close early.
所以我建议仅在他们尝试做一件事时共享连接。或者,如果您使用多进程,那么每个进程都会获得一个连接,同样遵循晚开、早关的原则。如果您正在进行顺序操作(比如在循环中),则在循环外打开和关闭。拥有全球连接可能会变得混乱。主要是因为现在你必须跟踪哪个函数在什么时候使用它,以及它试图用它做什么。
"cannot run command now" 的问题是因为您的键盘中断终止了活动连接。
关于你的问题的第一部分 - 无休止地可能在任何地方。 python 的每个实例都将获得自己的连接。因此,当您第二次 运行 它时,它应该获得自己的连接。打开一个 mysql 客户端并执行
show full processlist
看看发生了什么。