当前位置:  开发笔记 > 编程语言 > 正文

使用SQLAlchemy和sqlite嵌套事务

如何解决《使用SQLAlchemy和sqlite嵌套事务》经验,为你挑选了1个好方法。

我正在使用SQLAlchemy(和Elixir)用SQLite作为数据库后端在Python中编写应用程序.我使用代码启动一个新的事务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).

如何使嵌套事务生效?



1> Snorfalorpag..:

我在Windows上使用Python 3使用嵌套事务遇到了这个问题.我正在使用SQLite版本3.8.11,所以SAVEPOINT应该支持.显然安装pysqlite不是我的选择,因为它不支持Python 3.

几个小时后我的头撞在桌子上,我在文档中看到了这一部分:

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

在Database Locking Behavior/Concurrency一节中,我们引用了pysqlite驱动程序的各种问题,这些问题阻止了SQLite的几个功能正常工作.pysqlite DBAPI驱动程序有几个长期存在的错误,这些错误会影响其事务行为的正确性.在其默认操作模式下,SQLite功能(如SERIALIZABLE隔离,事务DDL和SAVEPOINT支持)不起作用,并且为了使用这些功能,必须采取解决方法.

问题本质上是驱动程序试图猜测用户的意图,无法启动事务并有时过早地结束它们,以尽量减少SQLite数据库的文件锁定行为,即使SQLite本身使用"共享"锁进行读取 - 只有活动.

SQLAlchemy默认选择不改变这种行为,因为它是pysqlite驱动程序的长期预期行为; 如果和当pysqlite驱动程序试图修复这些问题时,这将更多地成为SQLAlchemy默认的驱动程序.

好消息是,通过一些事件,我们可以完全实现事务支持,完全禁用pysqlite的功能并自己发布BEGIN.这是使用两个事件侦听器实现的:

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语句很有帮助(这在上面的例子中使用):

调试(显示)由SQLAlchemy发送到数据库的SQL命令

推荐阅读
TXCWB_523
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有