【问题标题】:Ways to avoid MySQLdb's "Commands out of sync; you can't run this command now" (2014) exception避免 MySQLdb 的“命令不同步;您现在无法运行此命令”(2014) 异常的方法
【发布时间】:2011-06-10 03:03:09
【问题描述】:

以下代码,使用 python 2.6.6 和 MySQLdb 1.2.2 导致 命令不同步;您现在无法运行此命令 MySQLdb 异常:

import MySQLdb

conn = MySQLdb.connect( db="test", user="root" )
cursor = conn.cursor( MySQLdb.cursors.DictCursor )

cursor.execute( "BEGIN; CREATE TABLE t1 ( t1_id INT PRIMARY KEY AUTO_INCREMENT ); COMMIT;" )
cursor.execute( "BEGIN; CREATE TABLE t2 ( t2_id INT PRIMARY KEY AUTO_INCREMENT ); COMMIT;" )

在执行第二个查询期间引发异常。正如我所读到的,该异常通常是由 MySQL 的 C API 实现的限制引起的,它不允许并发查询执行。

如果我在上述两个查询之间重新创建游标对象,问题就会得到解决,但不幸的是,该解决方案对我来说似乎并不完美。我对数据库连接和查询执行有一个非常简单的抽象,并且不希望在每次查询执行后重新创建游标,因为它会(据我了解)提交当前事务并可能产生其他副作用。

因此,我的问题是:还有哪些其他方法可以避免此异常?如何准备游标对象以执行下一个查询?也许Python DB API期望有一些方法,在使用其他数据库接口时会相对中立,在MySQLdb的情况下可以解决问题?

提前感谢您的时间和帮助:)

编辑: 发布问题后,我开始阅读 Python DB API 规范以了解游标破坏的副作用(我不再那么确定事务提交了 :)),我发现了以下替代解决方法:

cursor.execute( "BEGIN; CREATE TABLE t1 ( t1_id INT PRIMARY KEY AUTO_INCREMENT ); COMMIT;" )
while cursor.nextset() is not None: pass
cursor.execute( "BEGIN; CREATE TABLE t2 ( t2_id INT PRIMARY KEY AUTO_INCREMENT );

问题是我不知道它做了什么(它返回两次1,然后返回None)。我应该深入这个方向吗?我的意思是,我应该了解这些集合的概念以找到解决问题的方法吗?

【问题讨论】:

    标签: python mysql


    【解决方案1】:

    DB-API 尝试自己处理事务,在第一个命令上启动事务并拥有自己的 API 调用来提交它,所以:

    cursor.execute( "CREATE TABLE t1 ( t1_id INT PRIMARY KEY AUTO_INCREMENT )" )
    cursor.commit()
    cursor.execute( "CREATE TABLE t2 ( t2_id INT PRIMARY KEY AUTO_INCREMENT )" )
    cursor.commit()
    

    在我看来,这是 Python 的 DB-API 的一个严重的、明显的设计错误,使得在事务之外执行命令和对事务进行适当的控制变得非常麻烦,例如。使用 SQLite 的 BEGIN EXCLUSIVE TRANSACTION 之类的东西。就好像允许没有真正数据库经验的人设计 API...

    【讨论】:

    • +1,或者你可以设置 autocommit 为 true,默认是禁用的;像这样cursor.connection.autocommit(True), .
    • @singularity:但如果你这样做,你会在低级别改变 API 的行为——如果你将连接传递给第三方代码,这可能会咬你,因为例子。
    • @Glenn Maynard:不,它只会为我们在代码中创建的光标连接启用 autocommit 选项:),启用自动提交对在某些情况下,当我们想要实时节省而不是每次都这样做时 cursor.commit() ...
    • @singularity:它是:它导致 API 不再在事务中包装命令块,现在代码依赖于它是 DB-API 的默认行为。
    • @singularity:不,你没有抓住重点。您不会在自己的事务中运行每个操作;关键是允许用户自己启动和提交事务,这应该是,包括向BEGIN TRANSACTION 提供参数的能力以及在任何事务之外运行命令的能力(例如,Postgresql 的VACUUM 命令不能在事务中使用)。 API 不应该试图神奇地抽象出交易;这应该留给用户。您可以使用自动提交禁用此行为,但同样会破坏不期望的代码。
    猜你喜欢
    • 2013-12-27
    • 2012-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-19
    • 1970-01-01
    • 2019-07-04
    • 2012-12-01
    相关资源
    最近更新 更多