SQLAlchemy,scoped_session - 原始SQL INSERT不写入DB

时间:2014-08-25 11:02:05

标签: python mysql sqlalchemy pyramid

我有一个Pyramid / SQLAlchemy,MySQL python应用程序。 当我执行原始SQL INSERT查询时,没有任何内容写入数据库。 但是,在使用ORM时,我可以写入数据库。我阅读了文档,我读到了关于ZopeTransactionExtension的内容,阅读了大量的SO问题,但都无济于事。 到目前为止还没有工作:

  • transaction.commit() - 没有任何内容写入数据库。我确实意识到这个陈述对ZopeTransactionExtension来说是必要的,但它不会在这里发挥作用。
  • dbsession().commit - 由于我使用的是ZopeTransactionExtension,因此无法正常工作
  • dbsession().close() - 没有写任何内容
  • dbsession().flush() - 没有写任何内容
  • mark_changed(session) -

      

    文件" /home/dev/.virtualenvs/sc/local/lib/python2.7/site-packages/zope/sqlalchemy/datamanager.py",第198行,在join_transaction中   如果session.twophase:   AttributeError:' scoped_session'对象没有属性'""

  •   
  什么有效,但是不可接受,因为它没有使用scoped_session:

  • engine.execute(...)

我正在寻找如何使用scoped_session(我的代码中为dbsession())执行原始SQL

这是我的SQLAlchemy设置(models/__init__.py

def dbsession():
    assert (_dbsession is not None)
    return _dbsession

def init_engines(settings, _testing_workarounds=False):
    import zope.sqlalchemy
    extension = zope.sqlalchemy.ZopeTransactionExtension()
    global _dbsession

    _dbsession = scoped_session(
        sessionmaker(
            autoflush=True,
            expire_on_commit=False,
            extension=extension,
        )
    )

    engine = engine_from_config(settings, 'sqlalchemy.')
    _dbsession.configure(bind=engine)

这是我写的一个用于隔离问题的python脚本。它类似于问题发生的真实环境。我想要的是让下面的脚本将数据插入到DB中:

# -*- coding: utf-8 -*-
import sys
import transaction

from pyramid.paster import setup_logging, get_appsettings
from sc.models import init_engines, dbsession
from sqlalchemy.sql.expression import text


def __main__():

if len(sys.argv) < 2:
    raise RuntimeError()
config_uri = sys.argv[1]
setup_logging(config_uri)
aa = init_engines(get_appsettings(config_uri))

session = dbsession()
session.execute(text("""INSERT INTO
         operations (description, generated_description)
         VALUES ('hello2', 'world');"""))

print list(session.execute("""SELECT * from operations""").fetchall()) # prints inserted data
transaction.commit()

print list(session.execute("""SELECT * from operations""").fetchall()) # doesn't print inserted data

if __name__ == '__main__':
    __main__()

有趣的是,如果我这样做:

session = dbsession()
session.execute(text("""INSERT INTO
         operations (description, generated_description)
         VALUES ('hello2', 'world');"""))
op = Operation(generated_description='aa', description='oo')
session.add(op)

然后第一个打印输出原始SQL插入行(&#39; hello2&#39;&#39;&#39;&#39;),第二个打印输出两个行,实际上两行都插入到数据库中。

我无法理解为什么使用ORM插入以及原始SQL&#34;修复&#34;它

我真的需要能够在scoped_session上调用execute()以使用原始SQL将数据插入到数据库中。有什么建议吗?

1 个答案:

答案 0 :(得分:3)

自从我将原始sql与sqlalchemy混合以来已经有一段时间了,但无论何时混合它们,您都需要了解ORM幕后发生的事情。首先,检查autocommit标志。如果未正确配置zope事务,则ORM插入可能会触发提交。

实际上,在查看zope文档后,似乎手动执行语句需要额外的步骤。来自readme

  

默认情况下,zope.sqlalchemy将会话置于“活动”状态。他们是什么时候说的   第一次使用。 ORM写操作会自动将会话移动到   &#39;变更&#39;州。这可以避免不必要的数据库提交。有时它   必须通过SQL直接与数据库交互。它不是   可以猜测这样的操作是读还是写。所以我们   手动SQL语句写入时,必须手动将会话标记为已更改   到DB。

>>> session = Session()
>>> conn = session.connection()
>>> users = Base.metadata.tables['test_users']
>>> conn.execute(users.update(users.c.name=='bob'), name='ben')
<sqlalchemy.engine...ResultProxy object at ...>
>>> from zope.sqlalchemy import mark_changed
>>> mark_changed(session)
>>> transaction.commit()
>>> session = Session()
>>> str(session.query(User).all()[0].name)
'ben'
>>> transaction.abort()

似乎你没有这样做,所以transaction.commit什么也没做。