【问题标题】:combine SQLAlchemy Core and ORM get problems结合 SQLAlchemy Core 和 ORM 得到问题
【发布时间】:2017-02-11 15:06:51
【问题描述】:

如何结合 SQLAlchemy 的两个组件——核心(SQL 表达式)和 ORM ? 我有一些使用 ORM 映射器的表,而其他的只是 Table 对象,我想要 一个连接和一个事务处理两个

我有以下两个示例,但遇到了问题(结果与我交叉两种访问方式的查询不一致)。 一个使用自动提交会话,另一个使用默认会话。


session_autocommit=Session(bind=db,autocommit=True)
def f():
    with session_autocommit.begin() as trans:
        # ORM 
        x=session_autocommit.query(Mytable).filter(Mytable.id==1).first()
        # sql expression by SQLAlchemy Core 
        session_autocommit.execute(mytable.update().where(mytable.c.id==1)\
            .values(note=None)) 
        # update via ORM
        x.note='a'
f() # ok two update appear in log.
f() # ! only one update as below

x.note == 'a'
# the second run of f() returns False but should be True.

f() 第二次运行的日志说它只有一次更新 (note=None) ,第二次更新错过了?

INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
INFO sqlalchemy.engine.base.Engine SELECT mytable.id AS mytable_id, mytable.note AS mytable_note
FROM mytable 
WHERE mytable.id = %(id_1)s 
 LIMIT %(param_1)s
INFO sqlalchemy.engine.base.Engine {'param_1': 1, 'id_1': 1}
INFO sqlalchemy.engine.base.Engine UPDATE mytable SET note=%(note)s WHERE mytable.id = %(id_1)s
INFO sqlalchemy.engine.base.Engine {'id_1': 1, 'note': None}
INFO sqlalchemy.engine.base.Engine COMMIT

UPDATE第二个问题解决了。
感谢@univerio 的评论,我需要先flush 它才能正确执行执行顺序。由于我使用的是两个独立的 SQLAlchemy 机制。

session=Session(bind=db,autocommit=False)
# default session must rely commit to control transaction.

session.commit()
x=session.query(Mytable).filter(Mytable.id==1).first()
x.note='a'
session.execute(mytable.update().where(mytable.c.id==1)\
    .values(note=None)) 
session.commit()

x.note=='a'
# the test return True but should be None.

日志说两次更新的顺序不同?

INFO sqlalchemy.engine.base.Engine COMMIT
INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
INFO sqlalchemy.engine.base.Engine SELECT mytable.id AS mytable_id, mytable.note AS mytable_note
FROM mytable 
WHERE mytable.id = %(id_1)s 
 LIMIT %(param_1)s
INFO sqlalchemy.engine.base.Engine {'id_1': 1, 'param_1': 1}
INFO sqlalchemy.engine.base.Engine UPDATE mytable SET note=%(note)s WHERE mytable.id = %(id_1)s
INFO sqlalchemy.engine.base.Engine {'note': None, 'id_1': 1}
INFO sqlalchemy.engine.base.Engine SELECT mytable.id AS mytable_id
FROM mytable 
WHERE mytable.id = %(param_1)s
INFO sqlalchemy.engine.base.Engine {'param_1': 1}
INFO sqlalchemy.engine.base.Engine UPDATE mytable SET note=%(note)s WHERE mytable.id = %(mytable_id)s
INFO sqlalchemy.engine.base.Engine {'note': 'a', 'mytable_id': 1}
INFO sqlalchemy.engine.base.Engine COMMIT

【问题讨论】:

  • 我无法重现您的第一个案例。第二种情况是预期的,因为刷新是随着提交发生的;如果您在x.note = 'a' 之后执行session.flush(),您将获得预期的结果。
  • 感谢@univerio ,已编辑,第一种情况的问题是在第二次重复运行后发生的。

标签: python sql orm sqlalchemy relational-database


【解决方案1】:

在阅读了更多关于session 的信息后,我对此有了答案。


session有它的工作机制,一个是unit of work --

“对由 Session 维护的对象的所有更改都被跟踪 - 之前 再次查询数据库或在当前事务被查询之前 提交时,它会刷新对数据库的所有未决更改。这是 称为工作单元模式。” http://docs.sqlalchemy.org/en/latest/orm/session_basics.html

  • 第一个问题是因为unit of work,因此 SQLAlchemy 将跟踪更改的内容并巧妙地只执行真正需要的内容。结果是只需要一次更新。

  • 第二个问题通过手动session.flush() ORM 更新来解决,以获得正确的执行顺序。由于我使用了两种独立的 SQLAlchemy 机制,而且似乎 unit of work 也不适用于原始 SQL 表达式。

【讨论】:

    猜你喜欢
    • 2017-07-31
    • 2016-04-23
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 2014-04-26
    • 2017-04-02
    • 2011-02-27
    相关资源
    最近更新 更多