【问题标题】:How to add an event handler only fire once after transaction committed in sqlalchemy如何在 sqlalchemy 中提交事务后仅触发一次事件处理程序
【发布时间】:2016-09-08 06:34:05
【问题描述】:

我正在使用 sqlalchemy 编写一些函数。这些函数在事务内部调用,例如:

def create_order(session, *arg, **kw):
    # create order object
    order = Order(xxxx=xxx)
    session.add(order)

    # order extra operations
    order_extra_data = OrderExtraData(yyyy=yyyy)
    session.add(order_extra_data)

    # more operations
    ....

    # email should be sent to the order's owner 

成功创建订单后,应向用户发送电子邮件。但是在 create_order 结束时,事务还没有提交,可能会被后面的代码中止。所以这个函数不应该直接发送邮件。相反,它应该注册一个一次性事件处理程序,该处理程序仅在提交会话后触发(如果事务回滚或关闭,则不会触发和清除)。我该如何实现呢?

【问题讨论】:

    标签: events transactions sqlalchemy


    【解决方案1】:

    您可以使用once=True 监听会话after_commit 事件:

    def create_order(session, ...):
        ...
        @event.listens_for(session, "after_commit", once=True)
        def _send_email_after_commit(session):
            send_email()
    

    如果您预计回滚并在以后重用会话(并且在回滚后不触发侦听器),您还需要在发生回滚时删除该事件:

    def create_order(session, ...):
        ...
        @event.listens_for(session, "after_commit", once=True)
        def _send_email_after_commit(session):
            send_email()
    
        @event.listens_for(session, "after_soft_rollback", once=True)
        def _remove_event_listener_on_rollback(session, prev_transaction):
            event.remove(session, "after_commit", _send_email_after_commit)
    

    【讨论】:

    • 太好了,我也在阅读有关事件的文档。是否保证 after_commit 和 after_soft_rollback 被调用(如果直接调用 session.close() 会触发 after_soft_rollback 吗?)。为什么使用 after_soft_rollback 而不是 after_rollback?
    • @jayven 我相当肯定事务要么被提交 (after_commit) 要么被回滚 (after_soft_rollback)。我不确定的唯一情况是事务是否尚未开始,但这几乎从未发生过。 Session.close 也无关紧要,因为您将无法在会话关闭后重用会话(并且您创建的任何新会话都不会让您在过去附加到其他会话的侦听器)。使用after_soft_rollback,因为它是对应session.rollback()的事件; after_rollback 对应一个 SQL ROLLBACK
    • 谢谢你的解释,这对我帮助很大。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-23
    • 1970-01-01
    相关资源
    最近更新 更多