python - 使用 pyramid_tm 时,SQLAlchemy session.begin_nested() 应该与 transaction.commit() 一起提交吗?

标签 python sqlalchemy pyramid

我正在开发 Pyramid 应用程序,目前正在从 sqlite 迁移到 postgresql。我发现 postgresql 限制性更强的事务管理让我很不爽。

我正在使用 pyramid_tm,因为我觉得它很方便。我的大部分问题都发生在异步调用期间。我所拥有的是提供动态形式的 View 。这个想法是——如果我们得到一个对应于数据库行的 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) 中注册并在呈现我的 View 时调用

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. 可以在 session.begin_nested() 嵌套事务上执行 transaction.commit() 吗?我不确切地知道 SQLAlchemy 的结束位置和 pyramid_tm 的开始位置。如果我尝试提交 session ,我会收到一个异常,提示我只能使用事务管理器提交。另一方面,DBSession.rollback() 工作正常。
  2. 是否像这样处理

    try:
        #do something with db
    except:
        #oops, let's do something else
    

有意义吗?我感觉这是“pythonic”,但我不确定这种底层事务是否需要非 pythonic 方式。

最佳答案

在您的代码中调用 transaction.commit() 会提交 session 并导致您的 contact_person 对象在提交后稍后尝试使用它时过期。同样,如果您的 user 对象在提交的两边都被触及,您就会遇到问题。

如您所说,如果出现异常 (NoResultFound),则您的 session 现在无效。您正在寻找的是一个保存点,它支持事务,但不是直接通过 begin_nested。相反,您可以结合使用 transaction.savepoint()DBSession.flush() 来处理错误。

这里的逻辑是 flush 在数据库上执行 SQL,引发任何错误并允许您回滚保存点。回滚后, session 恢复,你可以继续你的快乐方式。尚未提交任何内容,在请求结束时将该工作留给 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)

关于python - 使用 pyramid_tm 时,SQLAlchemy session.begin_nested() 应该与 transaction.commit() 一起提交吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16710730/

相关文章:

python - SqlAlchemy 和 PostgreSql 日期时间更新

python - 我应该使用 Pylons 还是 Pyramid?

python - 如何找到女服务员发出 "task queue depth"警告的原因?

python - 如何在谷歌应用引擎中使用whois

python - 多余的 python 参数

python - 如何从Python中的JSON对象获取数据数组?

python - pycharm scrapy配置

python - 在 SQLAlchemy Declarative 中创建指向相关表的链接

python - 手动插入连接表继承模型的测试数据

Python Pyramid - URL 调度和遍历问题与哈希 (/)