为什么MySQLdb Connection上下文管理器不关闭游标?

编程入门 行业动态 更新时间:2024-10-09 14:19:21
本文介绍了为什么MySQLdb Connection上下文管理器不关闭游标?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

MySQLdb Connections具有一个基本的上下文管理器,可在 enter 上创建一个游标,回滚或在 exit 上提交,并且隐式不抑制异常.从连接源:

MySQLdb Connections have a rudimentary context manager that creates a cursor on enter, either rolls back or commits on exit, and implicitly doesn't suppress exceptions. From the Connection source:

def __enter__(self): if self.get_autocommit(): self.query("BEGIN") return self.cursor() def __exit__(self, exc, value, tb): if exc: self.rollback() else: selfmit()

那么,有谁知道为什么退出时光标未关闭?

So, does anyone know why the cursor isn't closed on exit?

起初,我以为是因为关闭游标并没有做任何事情,并且游标只具有close方法,以符合 Python DB API (请参见对此答案的评论).但是,事实是关闭游标会消耗掉剩余的结果集(如果有的话)并禁用游标.从光标源:

At first, I assumed it was because closing the cursor didn't do anything and that cursors only had a close method in deference to the Python DB API (see the comments to this answer). However, the fact is that closing the cursor burns through the remaining results sets, if any, and disables the cursor. From the cursor source:

def close(self): """Close the cursor. No further queries will be possible.""" if not self.connection: return while self.nextset(): pass self.connection = None

在退出时关闭光标非常容易,所以我不得不假设它不是故意这样做的.另一方面,我们可以看到,删除游标后,游标还是会关闭,所以我猜垃圾回收器最终会解决它.我对Python的垃圾回收了解不多.

It would be so easy to close the cursor at exit, so I have to suppose that it hasn't been done on purpose. On the other hand, we can see that when a cursor is deleted, it is closed anyway, so I guess the garbage collector will eventually get around to it. I don't know much about garbage collection in Python.

def __del__(self): self.close() self.errorhandler = None self._result = None

另一个猜测是,在某些情况下,您可能想在with块之后重新使用光标.但我想不出您为什么需要这样做的任何理由.您不能总是在光标的上下文内完成光标的使用,而只对下一个事务使用单独的上下文吗?

Another guess is that there may be a situation where you want to re-use the cursor after the with block. But I can't think of any reason why you would need to do this. Can't you always finish using the cursor inside its context, and just use a separate context for the next transaction?

非常清楚,此示例显然没有意义:

To be very clear, this example obviously doesn't make sense:

with conn as cursor: cursor.execute(select_stmt) rows = cursor.fetchall()

应该是:

with conn as cursor: cursor.execute(select_stmt) rows = cursor.fetchall()

这个例子也没有道理

# first transaction with conn as cursor: cursor.execute(update_stmt_1) # second transaction, reusing cursor try: cursor.execute(update_stmt_2) except: conn.rollback() else: connmit()

应该是:

# first transaction with conn as cursor: cursor.execute(update_stmt_1) # second transaction, new cursor with conn as cursor: cursor.execute(update_stmt_2)

再次,关闭退出时的游标有什么危害,不关闭它有什么好处?

推荐答案

直接回答您的问题:在with块结尾处关闭时,我看不到任何危害.我不能说为什么在这种情况下不这样做.但是,由于该问题缺乏活动,因此我在代码历史中进行了搜索,并提出了一些关于 可能 不会被调用:

To answer your question directly: I cannot see any harm whatsoever in closing at the end of a with block. I cannot say why it is not done in this case. But, as there is a dearth of activity on this question, I had a search through the code history and will throw in a few thoughts (guesses) on why the close() may not be called:

  • 很少有机会通过调用nextset()进行旋转,可能会引发异常-可能已经观察到并认为这是不希望的.这可能就是为什么较新版本的cursors.py 包含在内的原因close()中的这种结构:

  • There is a small chance that spinning through calls to nextset() may throw an exception - possibly this had been observed and seen as undesirable. This may be why the newer version of cursors.py contains this structure in close(): def close(self): """Close the cursor. No further queries will be possible.""" if not self.connection: return self._flush() try: while self.nextset(): pass except: pass self.connection = None

  • 存在(某种程度的远程)潜力,可能需要花费一些时间来浏览所有其余结果,无所作为.因此,可能不会调用close()以避免进行一些不必要的迭代.我想,您是否认为值得节省这些时钟周期是主观的,但是您可以按照如果没有必要,就不要这样做"的观点进行争论.

  • There is the (somewhat remote) potential that it might take some time to spin through all the remaining results doing nothing. Therefore close() may not be called to avoid doing some unnecessary iterations. Whether you think it's worth saving those clock cycles is subjective, I suppose, but you could argue along the lines of "if it's not necessary, don't do it".

    浏览sourceforge提交,该功能已通过此提交添加到了主干 a>在2007年,看来connections.py的此部分此后没有更改.这是基于此提交(其中包含消息

    Browsing the sourceforge commits, the functionality was added to the trunk by this commit in 2007 and it appears that this section of connections.py has not changed since. That's a merge based on this commit, which has the message

    如 docs.python/whatsnew/中所述,为with语句添加Python-2.5支持. pep-343.html 请测试

    您引用的代码从那以后再也没有改变过.

    And the code you quote has never changed since.

    这引起了我的最终想法-这可能只是第一次尝试/原型,它只是起作用了,因此从未改变过.

    This prompts my final thought - it's probably just a first attempt / prototype that just worked and therefore never got changed.

    更现代的版本

    您链接到源的旧版连接器.我注意到在此处处,有一个更活跃的同一个库,我在有关较新版本"的评论中链接了该库.在第1点.

    More modern version

    You link to source for a legacy version of the connector. I note there is a more active fork of the same library here, which I link to in my comments about "newer version" in point 1.

    请注意,此模块的最新版本已在cursor本身中实现了__enter__()和__exit__():请参见此处. __exit__()此处 做 调用self.close() ,也许这提供了一种更标准的方式来使用with语法,例如

    Note that the more recent version of this module has implemented __enter__() and __exit__() within cursor itself: see here. __exit__() here does call self.close() and perhaps this provides a more standard way to use the with syntax e.g.

    with conn.cursor() as c: #Do your thing with the cursor

    尾注

    NB 我想我应该补充一句,据我所知,一旦没有引用conn的地方,垃圾收集(也不是专家)将会是释放.此时,将没有对游标对象的引用,它也将被释放.

    End notes

    N.B. I guess I should add, as far as I understand garbage collection (not an expert either) once there are no references to conn, it will be deallocated. At this point there will be no references to the cursor object and it will be deallocated too.

    但是 调用cursor.close()并不意味着将被垃圾回收.它只是烧录结果并将连接设置为None.这意味着它不能被重复使用,但是不会立即被垃圾回收.您可以通过在with块之后手动调用cursor.close()然后说出打印cursor

    However calling cursor.close() does not mean that it will be garbage collected. It simply burns through the results and set the connection to None. This means it can't be re-used, but it won't be garbage collected immediately. You can convince yourself of that by manually calling cursor.close() after your with block and then, say, printing some attribute of cursor

    N.B. 2 我认为这是with语法的一种不寻常用法,因为conn对象仍然存在,因为它已经在外部范围内了-例如,与更常见的with open('filename') as f:在with块结束之后,没有任何对象随引用一起徘徊.

    N.B. 2 I think this is a somewhat unusual use of the with syntax as the conn object persists because it is already in the outer scope - unlike, say, the more common with open('filename') as f: where there are no objects hanging around with references after the end of the with block.

  • 更多推荐

    为什么MySQLdb Connection上下文管理器不关闭游标?

    本文发布于:2023-11-27 12:42:56,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1638126.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:游标   上下文   管理器   MySQLdb   Connection

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!