我正在开发一个金字塔应用程序,目前正处于从sqlite迁移到postgresql的过程中。我发现postgresql更严格的事务管理给了我一个糟糕的时间。
我正在使用pyramid_tm,因为我发现它很方便。我的大多数问题都发生在我的异步调用中。我所拥有的是提供动态表格的观点。我们的想法是 - 如果我们得到一个与数据库行对应的id,我们就会编辑现有的行。否则,我们正在增加一个新人。
@view_config(route_name='contact_person_form',
renderer='../templates/ajax/contact_person_form.pt',
permission='view',
request_method='POST')
def contact_person_form(request):
try:
contact_person_id = request.params['contact_person']
DBSession.begin_nested()
contact_person = DBSession.query(ContactPerson).filter(ContactPerson.id == contact_person_id).one()
transaction.commit()
except (NoResultFound, DataError):
DBSession.rollback()
contact_person = ContactPerson(name='', email='', phone='')
return dict(contact_person=contact_person)
我需要开始一个嵌套事务,因为否则我的惰性请求方法注册了config.add_request_method(get_user, 'user', reify=True)
并在呈现我的视图时被调用
def get_user(request):
userid = unauthenticated_userid(request)
if userid is not None:
user = DBSession.query(Employee).filter(Employee.id == userid).first()
return user
抱怨交易已被中断,并且将跳过员工上的SELECT。
我有两个问题:
transaction.commit()
嵌套事务上执行session.begin_nested()
是否可以?我并不确切SQLAlchemy结束的地方和pyramid_tm的开始。如果我尝试提交会话,我会得到一个异常,说我只能使用事务管理器提交。另一方面,DBSession.rollback()工作正常。处理此类似
try:
#do something with db
except:
#oops, let's do something else
有意义吗?我觉得这是'pythonic',但我不确定这个基础事务是否需要非pythonic手段。
答案 0 :(得分:3)
在代码中调用transaction.commit()
会提交会话,并在您尝试在提交后稍后使用它时导致contact_person
对象过期。同样,如果在提交的两面都触及了user
对象,那么您将遇到问题。
正如您所说,如果存在异常(NoResultFound
),那么您的会话现在无效。您正在寻找的是一个保存点,该事务支持,但不是直接通过begin_nested
。相反,您可以使用transaction.savepoint()
与DBSession.flush()
结合来处理错误。
这里的逻辑是flush
在数据库上执行SQL,引发任何错误并允许您回滚保存点。回滚后,会话恢复,你可以继续你的快乐方式。尚未提交任何内容,在请求结束时将该作业留给pyramid_tm。
try:
sp = transaction.savepoint()
contact_person = DBSession.query(ContactPerson)\
.filter(ContactPerson.id == contact_person_id)\
.one()
DBSession.flush()
except (NoResultFound, DataError):
sp.rollback()
contact_person = ContactPerson(name='', email='', phone='')
return dict(contact_person=contact_person)