在使用pyramid_tm时,应该使用transaction.commit()提交SQLAlchemy session.begin_nested()吗?

时间:2013-05-23 09:51:29

标签: python sqlalchemy pyramid

我正在开发一个金字塔应用程序,目前正处于从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。

我有两个问题:

  1. transaction.commit()嵌套事务上执行session.begin_nested()是否可以?我并不确切SQLAlchemy结束的地方和pyramid_tm的开始。如果我尝试提交会话,我会得到一个异常,说我只能使用事务管理器提交。另一方面,DBSession.rollback()工作正常。
  2. 处理此类似

    try:
        #do something with db
    except:
        #oops, let's do something else
    
  3. 有意义吗?我觉得这是'pythonic',但我不确定这个基础事务是否需要非pythonic手段。

1 个答案:

答案 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)