循环播放时可以使用相同的光标吗?

时间:2014-01-07 21:16:44

标签: python mysql database cursor mysql-python

我正在迭代SELECT结果,如下所示:

import MySQLdb

conn = MySQLdb.connect(host = 127.0.0.1, user = ...) # and so on
cur = conn.cursor()

cur.execute("SELECT * FROM some_table")

for row in cur:
    # some stuff I'm doing
    # sometimes I need to perform another SELECT here

问题是,我可以在cur循环中再次使用for,还是必须创建另一个游标(或者更多 - 另一个连接)?

我想我在这里缺少一些关于数据库或Python的基本知识......我实际上对这两者都很新。此外,我试图谷歌答案失败了。

我甚至会猜测自己我必须创建另一个游标,但我认为我已经实际使用了它一段时间之后我意识到这可能是错误的并且似乎有效。但我现在有点困惑,无法保证。所以我只是想确定一下。

谢谢。

1 个答案:

答案 0 :(得分:8)

您必须创建一个新游标。否则,cur现在会保留新“内部”选择的结果,而不是“外部”选择的结果。

可能仍在工作,具体取决于您的数据库和运气,但您不应指望它。我将尝试在下面解释。

但是,您不需要新连接。

所以:

cur.execute("SELECT * FROM some_table")

for row in cur:
    # some stuff I'm doing
    inner_cur = conn.cursor()
    inner_cur.execute("SELECT * FROM other_table WHERE column = row[1]")
    for inner_row in inner_cur:
        # stuff

那么,为什么它有时会起作用?

好吧,让我们来看看for row in cur:循环真正做了什么:

temp_iter = iter(cur)
while True:
    try:
        row = next(temp_iter)
    except StopIteration:
        break
    # your code runs here

现在,iter(cur)调用游标对象上的__iter__方法。那是做什么的?这是由cur决定的,它是数据库库提供的游标类型的对象。

显而易见的实现是返回某种迭代器,该迭代器具有对游标对象的引用,或对游标对象在封面下使用的同一行集合。例如,当您在列表上调用iter时会发生这种情况。

但是没有要求数据库库以这种方式实现其__iter__。它可以为迭代器创建行集的副本以供使用。或者,更合理的是,它可以使迭代器引用当前行集...但是当您下次调用execute时,更改光标本身以引用不同的。如果它那个,那么旧的迭代器继续读取旧的行集,你可以获得一个迭代新行集的新迭代器。

您不应该仅仅因为允许数据库库来执行此操作而依赖于此。但是你当然也不应该依赖它

更具体地说,想象一下这种类型:

class Cursor(object):
    # other stuff
    def __iter__(self):
        return iter(self.rowset)
    def execute(self, sql, *args):
        self.rowset = self.db.do_the_real_work(sql, *args)