Events 如何添加在sqlalchemy中提交事务后仅触发一次的事件处理程序

Events 如何添加在sqlalchemy中提交事务后仅触发一次的事件处理程序,events,transactions,sqlalchemy,Events,Transactions,Sqlalchemy,我正在使用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(ord

我正在使用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的末尾,事务尚未提交,可能会被稍后的代码中止。所以这个函数不应该直接发送邮件。相反,它应该注册一个一次性事件处理程序,该处理程序仅在会话提交后触发(如果事务是回滚或关闭的,则不触发并清除)。如何实现此功能?

您可以使用
once=True来侦听会话事件:

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)

好的thx,我也在读关于事件的文档。是否保证在提交后和软回滚后都会被调用(如果直接调用session.close(),是否会触发软回滚后?)。为什么要使用after_soft_rollback而不是after_rollback?@jayven我相当肯定,一个事务可以保证提交(
提交后
)或回滚(
提交后
)。我不确定的唯一情况是交易是否尚未启动,但这几乎从未发生过<代码>会话。关闭
也无关紧要,因为在会话关闭后,您将无法重用该会话(并且您创建的任何新会话都不会将侦听器附加到过去的其他会话)。在软回滚后使用
,因为它是对应于
会话的事件。回滚()
after_rollback
对应于SQL
rollback
。Thx对于您的解释,这对我帮助很大。