2016-05-12 10 views
1

sqlalchemyを使用していくつかの関数を書いています。これらの関数は、イベントハンドラを追加する方法は、sqlalchemyでコミットされたトランザクションの後に1回だけ発生します。

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の最後では、トランザクションはまだコミットされておらず、後のコードで中止される可能性があります。したがって、この関数は直接メールを送信すべきではありません。その代わりに、セッションがコミットされた後にのみ起動されるワンタイムイベントハンドラを登録する必要があります(トランザクションがロールバックまたはクローズの場合は起動せずクリアしないでください)。これをどのように実装できますか?

答えて

2

あなたは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) 
+0

私はイベントに関するドキュメントも読んでいます。 after_commitとafter_soft_rollbackのいずれかが呼び出されることを保証していますか?(session.close()を直接呼び出すとafter_soft_rollbackがトリガーされますか?)なぜafter_rollbackの代わりにafter_soft_rollbackを使用するのですか? – jayven

+0

@jayvenトランザクションがコミット(after_commit')またはロールバック( 'after_soft_rollback')されることが保証されていることはかなり確信しています。私が確信していない唯一のケースは、トランザクションがまだ開始されていない場合ですが、それはほとんど起こりません。 'Session.close'は、セッションが閉じられた後でセッションを再利用することができなくなるので、問題ではありません(作成した新しいセッションには、過去に他のセッションにアタッチしたリスナーはありません)。 'after_soft_rollback'は' session.rollback() 'に対応するイベントですので、これを使用してください。 'after_rollback'はSQLの' ROLLBACK'に対応します。 – univerio

+0

Thxあなたの説明のために、これは私をたくさん助けます。 – jayven

関連する問題