


Если две записи должны сохраниться вместе, выполняйте их в одной транзакции. При ошибке во второй операции первая тоже должна откатиться. На Mentoring.digital разберём этот сценарий с модулем sqlite3 в Python 3.12 и новее, без записи в рабочую базу.
Параметр autocommit=False задаёт управление транзакциями, совместимое с DB-API. В этом режиме commit и rollback завершают текущую транзакцию, после чего sqlite3 открывает новую. Не переносите пример на старую версию Python без проверки: параметр autocommit появился в 3.12.
Контекстный менеджер соединения фиксирует изменения при нормальном выходе и откатывает их при исключении. Само соединение конструкция with con не закрывает, поэтому закрытие вынесено в finally.
В учебной базе имя товара уникально. Вторая вставка нарушает ограничение, поэтому первая вставка из того же блока не сохраняется.
import sqlite3
con = sqlite3.connect(":memory:", autocommit=False)
try:
con.execute("CREATE TABLE items (name TEXT UNIQUE)")
con.commit()
try:
with con:
con.execute("INSERT INTO items VALUES (?)", ("book",))
con.execute("INSERT INTO items VALUES (?)", ("book",))
except sqlite3.IntegrityError:
print("transaction rolled back")
rows = con.execute("SELECT name FROM items").fetchall()
print(rows) # []
with con:
con.execute("INSERT INTO items VALUES (?)", ("pen",))
print(con.execute("SELECT name FROM items").fetchall())
# [('pen',)]
finally:
con.close()
Создание таблицы зафиксировано отдельно. Иначе откат мог бы затронуть и схему, созданную в незавершённой транзакции. Перехват IntegrityError находится снаружи блока with: исключение должно дойти до его выхода, чтобы менеджер увидел неуспех.
Знак ? обозначает параметр значения. Кортеж ("book",) содержит один элемент, запятая обязательна. Не вставляйте значение в SQL через f-строку: кавычки и содержимое ввода не должны менять структуру запроса.
Параметры не подставляют имена таблиц и столбцов. Если приложение разрешает выбирать столбец сортировки, сопоставляйте выбор с заранее разрешёнными именами. Транзакция отвечает за целостность изменений, а не заменяет проверку входных данных.
Замените повторяющийся book на notebook: обе записи должны сохраниться. Затем снова вызовите ошибку во второй вставке и сравните результат. Для файловой базы дополнительно проверьте чтение после повторного подключения и не держите транзакцию открытой во время ожидания действий пользователя.
Отработать этот сценарий можно на курсе Python с практическими задачами, а границы транзакций обсудить с наставником по Python.