Вложенные транзакции с SQLAlchemy и sqlite - PullRequest
5 голосов
/ 31 октября 2009

Я пишу приложение на Python, используя SQLAlchemy (и Elixir) с SQLite в качестве базы данных. Я начинаю новую транзакцию, используя код session.begin_transaction(), но когда я звоню session.rollback(), я получаю следующую ошибку:

sqlalchemy.exceptions.OperationalError: (OperationalError) no such savepoint: sa_savepoint_1 u'ROLLBACK TO SAVEPOINT sa_savepoint_1' []

Я также получаю похожую ошибку, вызывая session.commit(). Из того, что я могу сказать, sqlite поддерживает SAVEPOINTS (http://www.sqlite.org/lang_savepoint.html).

Как заставить работать вложенные транзакции?

Ответы [ 3 ]

7 голосов
/ 06 апреля 2016

Я столкнулся с этой проблемой, используя вложенные транзакции, используя Python 3 в Windows. Я использую SQLite версии 3.8.11, поэтому SAVEPOINT должна поддерживаться. Очевидно, установка pysqlite для меня не вариант, так как он не поддерживает Python 3.

После нескольких часов ударов головой о стол я наткнулся на этот раздел в документации:

http://docs.sqlalchemy.org/en/latest/dialects/sqlite.html#serializable-isolation-savepoints-transactional-ddl

В разделе Поведение / параллелизм блокировки базы данных мы ссылаемся на множество проблем, которые мешают нескольким Особенности SQLite от правильной работы. Pysqlite DBAPI драйвер имеет несколько давних ошибок, которые влияют на правильность его транзакционное поведение. В стандартном режиме работы SQLite такие функции, как SERIALIZABLE изоляция, транзакционный DDL и Поддержка SAVEPOINT не работает, и для их использования особенности, обходные пути должны быть приняты.

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

SQLAlchemy предпочитает не изменять это поведение по умолчанию, так как это долгожданное поведение драйвера pysqlite; если и когда Драйвер pysqlite пытается исправить эти проблемы, это будет больше драйвер по умолчанию для SQLAlchemy.

Хорошей новостью является то, что с помощью нескольких событий мы можем реализовать полная поддержка транзакций, полностью отключив функцию pysqlite и излучение НАЧИНАЕТСЯ. Это достигается с помощью двух событий слушателей:

from sqlalchemy import create_engine, event

engine = create_engine("sqlite:///myfile.db")

@event.listens_for(engine, "connect")
def do_connect(dbapi_connection, connection_record):
    # disable pysqlite's emitting of the BEGIN statement entirely.
    # also stops it from emitting COMMIT before any DDL.
    dbapi_connection.isolation_level = None

@event.listens_for(engine, "begin")
def do_begin(conn):
    # emit our own BEGIN
    conn.execute("BEGIN")

Добавление вышеупомянутых слушателей полностью решило проблему для меня!

Я опубликовал полный рабочий пример в виде сущности:

https://gist.github.com/snorfalorpagus/c48770e7d1fcb9438830304c4cca24b9

Я также нашел полезным занести в журнал операторы SQL (это используется в приведенном выше примере):

Отладка (отображение) команды SQL, отправленной в базу данных SQLAlchemy

3 голосов
/ 08 декабря 2009

Хотя sqlite, похоже, поддерживает вложенные транзакции через SAVEPOINT, это только с версии 3.6.8, выпущенной в январе 12 2009 года. Python, по крайней мере до v2.6, использует более ранние версии:

c:\svn\core\apps\general>python
Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit (Intel)] on win32
>>> import sqlite3 as s
>>> s.sqlite_version
'3.5.9'

Я полагаю, что вы можете установить PySqlite самостоятельно, и последняя версия поддерживает v3.6.12. Я не могу точно сказать, что это решит вашу проблему, но я думаю, что ответ объясняет, почему он не работает для вас сейчас.

0 голосов
/ 31 октября 2009

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

Ответ может заключаться в правильной настройке уровня изоляции при подключении.

Некоторое обсуждение этого вопроса здесь

...