3

我有一个 Pyramid Web 应用程序,其中包含一些从数据库读取数据并写入数据的表单页面。

该应用程序将 SQLAlchemy 与 PostgreSQL 数据库一起使用,这是我设置 SQLAlchemy 会话的方式:

from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
from zope.sqlalchemy import ZopeTransactionExtension

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))

当我处理一个表单时,我需要执行一个包含在 a 中的显式提交,try并查看该提交是否有效。我需要这个显式提交,因为我在 PostgreSQL 数据库中有可延迟的触发器(在提交时执行的检查),并且在某些情况下,没有错误是不可预测的。

一旦我成功提交了一个事务,例如添加一个 MyClass 的实例,我想获得这个实例的一些属性以及链接实例的一些属性。事实上,在提交之前我无法获取这些数据,因为它们是由数据库本身计算的。

我的问题是,当我使用transaction.commit()(在transaction包中)时,会话会自动关闭,我不能再使用该实例,因为它处于分离状态。文件证实了这一点。

因此,如文档中所述,我尝试使用以下会话设置:

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension(keep_session=True)))

但是,现在会话范围不再与 http 请求范围相同:在我的仅执行读取查询的 http 请求结束时不会发送 ROLLBACK。

那么,有没有办法让会话与 http 请求具有相同的范围但在提交时不会自动关闭?

4

1 回答 1

4

keep_session=True您可以通过ZTE 上的将会话与请求分离。但是,如果是这种情况,您可能还想在提交会话后使用对象,否则您会对新会话感到满意。因此,您还需要expire_on_commit=False在您的会话中。之后,您已经成功地将会话从 pyramid_tm 的生命周期中分离出来,您可以随意提交/中止。那么我们如何在不使用 pyramid_tm 的情况下将其重新附加到请求生命周期中呢?好吧,如果你把你DBSession的东西包装在一个不那么全局的东西中,这将使它作为一个请求范围的变量更易于管理,那会有所帮助。从那里,很明显会话何时创建,何时应该通过请求完成的回调销毁。以下是我的散文摘要:

def get_db(request):
    session = request.registry['db_session_factory']()
    def _closer(request):
        session.close()
    request.add_finished_callback(_closer)
    return session

def main(global_conf, **settings):
    config = Configurator()

    DBSession = sessionmaker(expire_on_commit=False, extension=ZopeTransactionExtension(keep_session=True))
    # look we don't even need a scoped_session anymore because it's not global, it's local to the request!

    config.registry['db_session_factory'] = DBSession

    config.add_request_method('db', get_db, reify=True)

def myview(request):
    db = request.db # creates, or reuses the session created for this request
    model = db.query(MyModel).first();
    transaction.commit()
    # model is still valid here
    return {}

当然,如果我们做这一切,中兴通讯可能根本帮不上你,你只想db.commit()自己使用和处理。如果发生异常,仍将调用已完成的回调,因此您不需要pyramid_tm 进行清理。

于 2013-04-22T20:18:13.520 回答