Я столкнулся с этой проблемой, используя вложенные транзакции, используя 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