В чем смысл класса "курсор" в psycopg?

Я хотел бы изменить некоторые данные с помощью вставок и обновлений. Из учебников psycopg похоже, что мне нужно

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

Psycopg по класса курсора кажется, имеет мало общего с курсорами, как определено postgres.

если мне распределить мой скрипт, который позволит создать подключение к основному модулю и некоторые функции работника (без резьбы, просто для модуляризации) я должен

  1. передать параметр связи к функциям и воссоздать курсор каждый раз. Часто ли возникают значительные накладные расходы при создании нового объекта cursor?

    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). Вот почему:

на cursor тип легкий, и просто создание его не делает ничего особенного, кроме создания нового объекта Python. Вы можете создавать, использовать (фиксация/откат) и уничтожать столько курсоров, сколько хотите, особенно если это поможет вам сохранить код чистым и организованным.

и cursors важны, когда вы работаете со сложной логикой, которая необходим доступ к данным, поступающим из нескольких, разных запросов: в этом случае курсор действует как держатель/итератор для ваших данных.

В конце концов, проходя по connection (ваш реальный дескриптор для бэкэнда) и сохранение курсоров локальными для конкретной функции/метода просто "чувствует себя правильно".


cursorс поддержкой with шаблон использования, который автоматически закроет их после завершения блока. Это может быть очень полезным шаблоном, когда вы выполняете компактные операции с курсорами.

в других случаях курсоры могут использоваться во всей функции, или может потребоваться несколько курсоров, и поэтому в этом случае with pattern будет иметь меньше смысла,и его лучше всего объявить на уровне функций.

также имейте в виду важность named cursors, где переплетаются курсоры psycopg и курсоры Postgres. Просто давая name атрибут значение в вызове конструктора, вы получите курсор на стороне сервера автоматически, который затем может быть повторен так же, как любая коллекция Python, и который выполняет фрагментированные выборки.

размер куска может быть изменен, хотя по умолчанию он извлекает блоки 2000. Это особенно важно при запросе больших таблиц, так как вы можете быстро запустить памяти клиентской стороны с огромным результирующим набором. psycopg абстракции, имеющие дело с курсорами Postgres напрямую, и следующий кусок извлекается прозрачно во время итерации курсора, когда это необходимо.

имейте в виду, что именованный курсор действительно может использоваться только для одной вещи-запроса, который вы затем повторяете; если вы попытаетесь выполнить другой запрос на том же курсоре, он, если память служит, выдаст исключение. С помощью безымянных курсоров вы можете повторно использовать один и тот же курсор выполняется, как только вы закончите с результатами.

Я обычно использую именованные курсоры для любых запросов, которые, по моему мнению, могут даже иметь шанс вернуть довольно большой результирующий набор, и неназванные курсоры для небольших запросов и других команд, таких как обновления, удаления, создание таблиц и т. д.


на спецификация API БД Python говорит:

"курсор базы данных ... используется для управления контекстом операции выборки."

поэтому, глядя на модульность, кажется, что, если ваша функция не нуждается в результатах предыдущей операции, было бы более целесообразно создать новые курсоры и либо закрыть их, либо позволить им быть закрытыми самостоятельно, когда они покидают область действия. Если у вас есть работы, которые вы повторяете много раз, и уверены, что воссоздание курсора приведет к накладным расходам, вы всегда можете создать вспомогательный класс, который обертывает курсор вместо простой вспомогательной функции.

однако все три ваших метода должны работать нормально. Я лично написал код, используя стиль №2, хотя я согласен, что он кажется худшим из них.