psycopg中`cursor`类的作用是什么?
我想用INSERT和UPDATE来修改一些数据。从psycopg的教程来看,我需要
cur = connection.cursor()
cur.execute(my_insert_statement)
connection.commit()
Psycopg的游标类似乎和Postgres定义的游标关系不大。
如果我把我的脚本模块化,在主模块中创建一个连接,然后再写一些工作函数(不涉及线程,只是为了模块化),我应该
把连接参数传给函数,每次都重新创建游标。频繁创建新的游标对象会有显著的开销吗?
def process_log_file(self, connection):
同时传递连接和游标 - 这样会让函数的参数和实现变得不必要地复杂
def process_log_file(self, connection, cursor):
只传递游标作为参数,然后用
mycursor.connection.commit()
来提交def process_log_file(self, cursor):
3 个回答
Python数据库API规范中提到:
“数据库游标……用于管理获取操作的上下文。”
从模块化的角度来看,似乎除非你的函数需要之前操作的结果,否则创建新的游标会更合理,之后可以选择关闭它们,或者让它们在超出作用域时自动关闭。如果你有一个需要重复多次的操作,并且确定重新创建游标会带来额外的开销,你可以考虑创建一个帮助类来包装游标,而不是简单的帮助函数。
不过,你提到的三种方法都应该能正常工作。我个人使用过第二种风格的代码,虽然我同意它似乎是三者中最差的。
cursor
(游标)支持一种叫做with
的用法,这种用法会在代码块执行完后自动关闭游标。这种方式在你需要进行简单操作时非常有用。
但有时候,游标可能需要在一个函数中多次使用,或者需要使用多个游标,这种情况下用with
就不太合适了,最好是在函数的范围内声明游标。
另外,要记住命名游标
的重要性,这个概念是psycopg游标和Postgres游标结合的地方。只需在创建游标时给name
属性赋值,你就会自动得到一个服务器端的游标,这个游标可以像处理任何Python集合一样进行迭代,并且会分块获取数据。
你可以调整每块获取的数据量,默认情况下是每次获取2000条。这在查询大表时特别重要,因为如果结果集很大,你可能会很快耗尽客户端的内存。psycopg会帮你处理Postgres游标,下一块数据会在你迭代游标时自动获取。
要记住,命名游标实际上只能用于一件事——就是执行一个查询并进行迭代;如果你尝试在同一个游标上执行另一个查询,可能会抛出异常。而非命名游标在处理完结果后可以重复使用。
我通常会对可能返回较大结果集的查询使用命名游标,而对小查询和其他命令(比如更新、删除、创建表等)使用非命名游标。
这三种方法都可以用(主要是个人喜好问题),但我更喜欢第一种。原因如下:
cursor
类型比较轻量,创建它并不会做什么特别的事情,只是生成一个新的Python对象。你可以随意创建、使用(提交/回滚)和销毁多个游标,特别是如果这样能帮助你保持代码的整洁和有序。
而且,当你处理复杂的逻辑,需要从多个不同的查询中获取数据时,cursor
就显得很重要:在这种情况下,游标就像是你数据的容器或迭代器。
最后,把connection
(你与后台的真实连接)传来传去,并把游标保持在特定的函数或方法内部,这样做“感觉更对”。