psycopg2操作错误:游标不存在。

15

我正在尝试实现一个服务器端游标,以便在从数据库获取大量数据时“绕过”Django ORM的弱点。 但我不明白命名游标应该如何定义,因为我的当前代码似乎无法正常工作。我是这样定义游标的:

id = 'cursor%s' % uuid4().hex
connection = psycopg2.connect('my connection string here')
cursor = connection.cursor(id, cursor_factory=psycopg2.extras.RealDictCursor)

光标似乎可以工作,因为它可以被迭代并返回预期的记录作为Python字典,但是当我尝试关闭它(cursor.close())时,我会遇到异常:

psycopg2 OperationalError: cursor *the generated cursor id* does not exist

这TM是什么?那我用来从数据库中检索信息的对象是什么? 如果我定义的游标在我的数据库中找不到,那么psycopg2是否使用回退默认(未命名)游标(如果是这样...我的大问题是:在使用psycopg2之前必须在db级别定义一个游标吗?)我很困惑,你能帮帮我吗?


6
如果你看到这条信息,可能的原因之一是因为你没有运行迁移(比如在拉取同事的更改后),从而导致 Django 中的某些内容崩溃,杀死了游标并隐藏在这个错误下面。请确保在使用 Django 时及时运行迁移。 - btown
4个回答

20

我犯了一个非常简单而愚蠢的错误,忘记在运行 ./manage.py test 之前运行 ./manage.py makemigrations./manage.py migrate,导致出现了这个错误。

(我知道这并没有回答原始问题,但因为这是 Google 的第一个结果,所以我想做出贡献。希望这样做可以。)


这解决了我的问题,我忘记做迁移了,django rest的单元测试没有显示任何相关错误,但主应用程序出现了问题。 - nck
我又犯了一个愚蠢的错误,虽然我已经运行了 makemigrations,但是我错误地给迁移文件添加了一个.py.py扩展名。我意识到通常我们不需要为迁移文件命名,但在我的情况下,我需要在 minikube 集群上运行迁移,然后再复制到我的本地文件系统上。 - whatapalaver

13

我遇到了同样的问题,这个参数会有什么后果?我看到Django查询集的iterator函数会受到影响。谢谢。 - Florent
1
当使用query.iterator()时,如果没有设置这个标志(仅适用于PostgreSQL和Oracle),它将在内存中加载整个数据集进行迭代。而设置了SERVER_SIDE_CURSORS后,它将按块加载数据,从而在此类迭代中实现更低的内存使用。具体降低多少内存使用取决于您的应用程序和数据集。我发现,在大多数情况下禁用服务器端游标不会对性能产生影响。例如,在Django管理界面中,数据以页面形式显示,禁用服务器端游标不会带来任何性能差异。 - Dmitry P.

12

在我尝试使用Pytest测试我的模型时,出现了问题。

解决问题的方法是重置测试单元的数据库。我使用了 --create-db 命令:

pytest backend/test_projects/partners/test_actions.py --create-db

5

来自 psycopg2 文档:

“通常情况下,命名游标在创建时不会使用 WITH HOLD ,这意味着它们只存在于当前事务中。在提交(commit())之后尝试从命名游标中获取数据,或当连接的事务隔离级别设置为 AUTOCOMMIT 时创建命名游标将导致异常。”

也就是说,这些游标不需要显式关闭。

http://initd.org/psycopg/docs/usage.html#server-side-cursors


嗯...我之前读过这句话,但实话实说,我没像你写的那样理解它...我担心内存泄漏,既然已经有close方法了,我不明白为什么不应该调用它。此外,我立即作为测试调用它,所以我应该处于相同的事务中...或者我错了吗? - daveoncode
我必须说我不确定。作为一个测试,尝试将无保留参数设置为True,看看是否可以在没有任何异常的情况下关闭游标。 - Talvalin
1
经过几个小时的测试、调试和阅读,我可以说我不必关闭游标,但我确实需要记得关闭它们正在使用的连接... 我创建了一些不错的包装类 :) - daveoncode
@daveoncode:我遇到了同样的问题,现在我想知道关闭连接是否真的必要,或者只需提交即可正确关闭游标?从Talvalin的答案中,我会推断出后者,但从你的评论中,是前者。提前致谢。 - leoschet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接