使用SQLAlchemy和sqlite嵌套事务

时间:2009-10-31 16:28:41

标签: python sqlite sqlalchemy python-elixir

我正在使用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)。

如何让嵌套交易有效?

3 个答案:

答案 0 :(得分:7)

我在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

  

在数据库锁定行为/并发部分中,我们参考   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语句很有帮助(这在上面的例子中使用):

Debugging (displaying) SQL command sent to the db by SQLAlchemy

答案 1 :(得分:3)

虽然sqlite看起来似乎通过SAVEPOINT支持嵌套事务,但它只是从version 3.6.8, released 2009 Jan 12开始。 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。我不能肯定地说这会解决你的问题,但我相信答案解释了为什么它现在不适合你。

答案 2 :(得分:0)

SQLAlchemy使用pysqlite与SQLite数据库进行交互,如果我没有弄错,pysqlite默认会将你在事务中发送的任何查询包装起来。

答案可能在于连接时正确设置隔离级别。

Some discussion about that over here