Для чего нужен commit, connection, cursor и close?
📁 итератор, python, пример
Базовый пример
import psycopg2# Connect to an existing databaseconn = psycopg2.connect(""dbname=test user=postgres"")# Open a cursor to perform database operationscur = conn.cursor()# Execute a command: this creates a new tablecur.execute(""CREATE TABLE test (id serial PRIMARY KEY, num integer, data varchar);"")# Pass data to fill a query placeholders and let Psycopg perform# the correct conversion (no more SQL injections!)cur.execute(""INSERT INTO test (num, data) VALUES (%s, %s)"",... (100, ""abc'def""))# Query the database and obtain data as Python objectscur.execute(""SELECT * FROM test;"")cur.fetchone()# Make the changes to the database persistentconn.commit()# Close communication with the databasecur.close()conn.close()Для каких нужд используется cur.close(), conn.commit(), conn.close? В чём их отличия?
Например conn.commit(), как указано в примере, применяет изменения. Но кажется логичнее, что за это будет отвечать курсор, потому как именно он является итератором по данным.
Судя по той же документации, правильный шаблон использования будет примерно такой:
conn = psycopg2.connect(DSN)try: with conn: with conn.cursor() as curs: curs.execute(SQL1) with conn: with conn.cursor() as curs: curs.execute(SQL2)finally: conn.close()Что тут имеется в виду.
connectionживёт столько, сколько нужно вам для ваших операций, если у вас операции с базой идут подряд -connectionне надо закрывать и переоткрывать; но если вы поработали с базой, а потом у вас перерыв - вы, например, перемалываете какие-то данные и пока базу не пишете и не читаете, тоconnectionлучше закрыть, чтобы она ушла в пул и другим процессам, работающим с базой, хватило этих самыхconnection; и да -connectionлучше закрывать в конце работы с ней и делать это наверняка (черезtry/finally), чтобы точно освободить связанные с ней ресурсыtransactionлучше создавать и закрывать с помощью блокаwith conn:- если не будет брошено исключение в течении работы блокаwith, то будет автоматически сделанcommit, а если будет исключение - будет выполненrollback; в одном блоке транзакции нужно объединять некий неразрывный блок работы с базой, который должен быть откачен целиком в случае неудачи, а в случае успешного завершения запись данных этого блока опять же должна представлять из себя в базе фрагмент данных, который ничего не поломает, будучи записанным в базу сам по себеcursor- похоже, в приведённом мной шаблоне использования это просто объект, который позволяет выполнять любые операции записи/чтения внутри одной транзакции и он сам закроется по окончании блокаwith conn.cursor() as curs:
Немного странно, что в приведённом вами примере без with курсор получается закрывается уже после commit, видимо, можно делать и так и так. Если курсор не закрывать самому, то он, видимо, остаётся открытым всё время существования connection. Но опять же, согласно документации, лучше курсор обязательно закрыть (и удобнее сделать это неявно с помощью блока with), чтобы он точно освободил какие-то ресурсы, которые на него выделены. Хотя, наверняка, закрытие connection и так освободит все ресурсы.
В общем, мне кажется, тут есть довольно большая свобода выбора шаблона, однако, блоки with позволяют более чётко разделить этапы работы программы с базой, если таковые этапы имеют место быть.
P.S. Конкретно по вашим вопросам отдельно:
Я напихал в БД 20000 записей при помощи 100 батчей. Нужно ли мне создавать новое соединение?
Если вы работаете с базой непрерывно, то новое соединение создавать не нужно.
А курсор? При этом, я считаю, что у меня будут ещё записи.
Опять же - это зависит от того, планируете ли вы держать и дальше открытым соединение, можно ли вашу работу записывать в базу по частям, и какой шаблон работы с базой вы выберете. При непрерывной работе с базой похоже можно открыть соединение и курсор один раз, а потом, при необходимости, делать коммиты после каждого куска выполненной работы (если она в вашем случае может быть записана в базу этими кусками и ничего при этом не поломается).
P.P.S. Отвечая на тему вопроса - в той же документации написано, что если не включен autocommit mode, при котором connection сам делает commit после каждой операции с курсором, то если не сделать после операций с курсором явный commit и при этом закрыть connection, то можно остаться в результате с грязными данными - состояние ваших данных в базе будет неопределённое (но это сильно зависит от конкретной базы данных), в худшем случае транзакция может вообще подвиснуть и залочить дальнейшие операции с базой до принудительной перезагрузки сервера БД. Нормальная БД в случае потери коннекшена, конечно, сделает rollback, но лучше до такого в любом случае не доводить.
Войдите чтобы оставить ответ