我正在使用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)。
如何让嵌套交易有效?
答案 0 :(得分:7)
我在Windows上使用Python 3使用嵌套事务遇到了这个问题。我使用SQLite版本3.8.11,因此应支持SAVEPOINT
。显然安装pysqlite不是我的选择,因为它不支持Python 3.
在桌子上敲了几个小时后,我在文档中看到了这一部分:
在数据库锁定行为/并发部分中,我们参考 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默认会将你在事务中发送的任何查询包装起来。
答案可能在于连接时正确设置隔离级别。