代码之家  ›  专栏  ›  技术社区  ›  Jon

使用SQLAlchemy和sqlite的嵌套事务

  •  5
  • Jon  · 技术社区  · 15 年前

    我正在用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() http://www.sqlite.org/lang_savepoint.html ).

    如何使嵌套事务工作?

    3 回复  |  直到 11 年前
        1
  •  10
  •   Snorfalorpagus    8 年前

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

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

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

    在数据库锁定行为/并发一节中,我们将参考 pysqlite驱动程序的一系列问题 SQLite的功能无法正常工作。pysqlite DBAPI驱动程序 它的正确性有几个长期的影响 交易行为。在其默认操作模式中,SQLite 诸如可序列化隔离、事务DDL和 保存点支持是不起作用的,为了使用这些 功能,必须采取变通办法。

    问题的实质是,司机试图猜测 用户的意图,无法启动事务,有时会终止它们 为了使SQLite数据库文件最小化,过早地 锁定行为,即使SQLite本身使用共享锁 只读活动。

    pysqlite驱动程序的长期预期行为;如果 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语句很有帮助(在上面的示例中使用):

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

        2
  •  3
  •   Peter Hansen    15 年前

    虽然sqlite看起来确实支持通过SAVEPOINT进行嵌套事务,但它只在 version 3.6.8, released 2009 Jan 12

    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。我不能肯定这会解决你的问题,但我相信答案可以解释为什么它现在对你不起作用。

        3
  •  0
  •   Dirk Stoop    15 年前

    SQLAlchemy使用pysqlite与SQLite数据库交互,如果我没搞错的话,pysqlite默认情况下会将您在事务中发送的任何查询打包。

    Some discussion about that over here