我有以下代码:
def executeQuery(conn, query):
cur = conn.cursor()
cur.execute(query)
return cur
def trackTagsGenerator(chunkSize, baseCondition):
""" Returns a dict of trackId:tag limited to chunkSize. """
sql = """
SELECT track_id, tag
FROM tags
WHERE {baseCondition}
""".format(baseCondition=baseCondition)
limit = chunkSize
offset = 0
while True:
trackTags = {}
# fetch the track ids with the coresponding tag
limitPhrase = " LIMIT %d OFFSET %d" % (limit, offset)
query = sql + limitPhrase
offset += limit
cur = executeQuery(smacConn, query)
rows = cur.fetchall()
if not rows:
break
for row in rows:
trackTags[row['track_id']] = row['tag']
yield trackTags
我想这样用:
for trackTags in list(trackTagsGenerator(DATA_CHUNK_SIZE, baseCondition)):
print trackTags
break
此代码产生以下错误,甚至没有获取一大块轨道标记:
Exception _mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this command now") in <bound method SSDictCursor.__del__ of <MySQLdb.cursors.SSDictCursor object at 0x10b067b90>> ignored
我怀疑是因为我在生成器函数的循环体中有查询执行逻辑。
有人能告诉我如何使用mysqldb以这种方式获取数据块吗?
答案 0 :(得分:1)
我很确定这是因为它可能遇到你有两个问题的情况 由于产量而同时运行。取决于你如何调用函数(线程,异步等)。我很确定你的光标也可能被破坏了吗?
同样,你通过使用基本上是printf插入baseConditional来打开自己(对不起,但我不能在这部分上涂糖)可怕的SQL注入漏洞。请查看DB-API的参数替换文档以获取帮助。
产量不会在这里节省你的时间或精力,完整的sql命令总是需要在你获得单个结果之前运行。 (因此你使用LIMIT和OFFSET使它更友好,荣誉)
即。有人在你输出一些数据时更新表格,在这个特殊情况下 - 而不是世界末日。在许多其他方面,它变得丑陋。
如果你只是四处闲逛而你想让它“正确 - 现在 - 该死”,那么它可能会修改executeQuery:
def executeQuery(conn, query):
cur = conn.cursor()
cur.execute(query)
cur = executeQuery(smacConn, query)
rows = cur.fetchall()
cur.close()
return rows
有一件事也有点跳出来 - 你定义了trackTags = {},但是你更新了tagTrackIds,并且产生了trackTags ..这将永远是空的dict。
我的建议是,如果你只是想让一个爱好项目工作,那就不用担心自己编写SQL的麻烦了。请查看Elixir之上构建的SQLAlchemy。
使用ORM(对象关系映射器)可以更加友好地介绍数据库。在Python中定义对象的外观,并让它自动为您生成模式 - 并且能够以Pythonic方式添加/修改/删除内容真的很漂亮。
如果你真的需要异步,请查看ultramysql python模块。
答案 1 :(得分:1)
使用SSDictCursor
,在MySQL-API端映射到mysql_use_result()
。这要求您在发出新命令之前先读出完整的结果。
因为在你收到第一块数据之前就已经发生了这样的事情:你是否确定在执行这部分代码之前查询的上下文中不会发生这种情况?最后一个查询的结果可能仍然在行中,并且执行下一个查询(即,此上下文中的第一个)可能会破坏事物......