psycopg中`cursor`类的作用是什么?

15 投票
3 回答
4029 浏览
提问于 2025-04-18 04:53

我想用INSERT和UPDATE来修改一些数据。从psycopg的教程来看,我需要

cur = connection.cursor()
cur.execute(my_insert_statement)
connection.commit()

Psycopg的游标类似乎和Postgres定义的游标关系不大。

如果我把我的脚本模块化,在主模块中创建一个连接,然后再写一些工作函数(不涉及线程,只是为了模块化),我应该

  1. 把连接参数传给函数,每次都重新创建游标。频繁创建新的游标对象会有显著的开销吗?

    def process_log_file(self, connection):
    
  2. 同时传递连接和游标 - 这样会让函数的参数和实现变得不必要地复杂

    def process_log_file(self, connection, cursor):
    
  3. 只传递游标作为参数,然后用mycursor.connection.commit()来提交

    def process_log_file(self, cursor):
    

3 个回答

1

Python数据库API规范中提到:

“数据库游标……用于管理获取操作的上下文。”

从模块化的角度来看,似乎除非你的函数需要之前操作的结果,否则创建新的游标会更合理,之后可以选择关闭它们,或者让它们在超出作用域时自动关闭。如果你有一个需要重复多次的操作,并且确定重新创建游标会带来额外的开销,你可以考虑创建一个帮助类来包装游标,而不是简单的帮助函数。

不过,你提到的三种方法都应该能正常工作。我个人使用过第二种风格的代码,虽然我同意它似乎是三者中最差的。

2

cursor(游标)支持一种叫做with的用法,这种用法会在代码块执行完后自动关闭游标。这种方式在你需要进行简单操作时非常有用。

但有时候,游标可能需要在一个函数中多次使用,或者需要使用多个游标,这种情况下用with就不太合适了,最好是在函数的范围内声明游标。

另外,要记住命名游标的重要性,这个概念是psycopg游标和Postgres游标结合的地方。只需在创建游标时给name属性赋值,你就会自动得到一个服务器端的游标,这个游标可以像处理任何Python集合一样进行迭代,并且会分块获取数据。

你可以调整每块获取的数据量,默认情况下是每次获取2000条。这在查询大表时特别重要,因为如果结果集很大,你可能会很快耗尽客户端的内存。psycopg会帮你处理Postgres游标,下一块数据会在你迭代游标时自动获取。

要记住,命名游标实际上只能用于一件事——就是执行一个查询并进行迭代;如果你尝试在同一个游标上执行另一个查询,可能会抛出异常。而非命名游标在处理完结果后可以重复使用。

我通常会对可能返回较大结果集的查询使用命名游标,而对小查询和其他命令(比如更新、删除、创建表等)使用非命名游标。

15

这三种方法都可以用(主要是个人喜好问题),但我更喜欢第一种。原因如下:

cursor类型比较轻量,创建它并不会做什么特别的事情,只是生成一个新的Python对象。你可以随意创建、使用(提交/回滚)和销毁多个游标,特别是如果这样能帮助你保持代码的整洁和有序。

而且,当你处理复杂的逻辑,需要从多个不同的查询中获取数据时,cursor就显得很重要:在这种情况下,游标就像是你数据的容器或迭代器。

最后,把connection(你与后台的真实连接)传来传去,并把游标保持在特定的函数或方法内部,这样做“感觉更对”。

撰写回答