我有以下代码:
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 以这种方式获取数据 block 吗?
最佳答案
我很确定这是因为它可能会遇到有两个查询的情况 由于产量而同时运行。根据您调用函数的方式(线程、异步等),我很确定您的光标也可能会被破坏?
此外,您实际上是通过使用 printf 插入 baseConditional 来暴露自己(抱歉,但我无法粉饰这部分)可怕的 SQL 注入(inject)漏洞。查看 DB-API 的参数替换文档以获取帮助。
Yield 根本不会为您节省时间或精力,在您获得单个结果之前,始终需要运行完整的 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.. 这将永远是空的字典。
我的建议是,如果您只是想让一个业余爱好项目发挥作用,就不要为手写 SQL 的麻烦而烦恼。看看Elixir它建立在 SQLAlchemy 之上。
使用 ORM(对象关系映射器)可以更友好地介绍数据库。在 Python 中定义对象的外观,并让它自动为您生成模式 - 并且能够以 Pythonic 方式添加/修改/删除内容真的很漂亮。
如果您确实需要异步,请查看 ultramysql python 模块。
关于Python 使用生成器获取 MySQLdb 结果 block - 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13343432/