Python 如何获取由zope.transaction管理的SQLAlchemy会话,该会话与http请求具有相同的作用域,但在提交时不会自动关闭?
我有一个金字塔式的web应用程序,其中有一些表单页,可以从数据库中读取数据,也可以向数据库中写入数据 该应用程序将SQLAlchemy与PostgreSQL数据库一起使用,下面是我如何设置SQLAlchemy会话的:Python 如何获取由zope.transaction管理的SQLAlchemy会话,该会话与http请求具有相同的作用域,但在提交时不会自动关闭?,python,transactions,sqlalchemy,pyramid,zope,Python,Transactions,Sqlalchemy,Pyramid,Zope,我有一个金字塔式的web应用程序,其中有一些表单页,可以从数据库中读取数据,也可以向数据库中写入数据 该应用程序将SQLAlchemy与PostgreSQL数据库一起使用,下面是我如何设置SQLAlchemy会话的: from sqlalchemy.orm import scoped_session from sqlalchemy.orm import sessionmaker from zope.sqlalchemy import ZopeTransactionExtension DBSes
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
from zope.sqlalchemy import ZopeTransactionExtension
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
在处理表单时,我需要执行try
中包含的显式提交,并查看提交是否有效。我需要这种显式的提交,因为我在PostgreSQL数据库中有(在提交时执行的检查),并且在某些情况下,没有错误是不可预测的
一旦我成功提交了一个事务,例如添加了一个MyClass实例,我想获得这个实例上的一些属性以及链接实例上的一些属性。实际上,我无法在提交之前获取这些数据,因为它们是由数据库本身计算的
我的问题是,当我使用transaction.commit()
(在transaction
包中)时,会话会自动关闭,我无法再使用实例,因为它处于分离状态。证实了这一点
因此,如文档中所述,我尝试使用以下会话设置:
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension(keep_session=True)))
但是,现在会话作用域不再与http请求作用域相同:只执行读取查询的http请求结束时不会发送回滚
那么,有没有办法让会话与http请求具有相同的作用域,但在提交时不会自动关闭?您可以通过中兴通讯上的
keep_session=True
将会话与请求分离。但是,如果是这种情况,您可能还希望在提交会话后使用对象,否则您会对新会话感到满意。因此,您还需要在会话中使用expire\on\u 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在之后进行清理。正如我所编辑的,这更像是zope.transaction/pyramid集成问题。您可能希望在金字塔邮件列表上请求更快的响应。它可以完美地工作,除非我的提交在try
块中失败。实际上,我在除
块中执行了事务.abort()
,但这似乎不够,因为当我再次尝试使用该会话时,我会收到一个错误:InvalidRequestError:由于刷新期间的前一个异常,该会话的事务已回滚。要使用此会话开始新事务,请首先发出Session.rollback()。最初的异常是…
。添加request.db.rollback()
解决了问题,但我不得不同时使用Transaction.abort()
和Session.rollback()
,这两种方法看起来都不干净。如果你在做这些事情,我不确定中兴通讯是否在帮助你。没错,我只是为了理解而问。