2016-05-12 4 views
1

feuern Ich schreibe einige Funktionen mit sqlalchemy. Diese Funktionen werden innerhalb der Transaktion wie folgt aufgerufen:Wie füge ich einen Event-Handler nur einmal nach der Transaktion in 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 

Nachdem die Bestellung erfolgreich erstellt wurde, sollte eine E-Mail an den Benutzer gesendet werden. Am Ende von create_order ist die Transaktion jedoch noch nicht festgeschrieben und wird möglicherweise durch späteren Code abgebrochen. Diese Funktion sollte also keine E-Mails direkt senden. Stattdessen sollte ein einmaliger Ereignishandler registriert werden, der erst ausgelöst wird, nachdem die Sitzung festgeschrieben wurde (und nicht ausgelöst und gelöscht wird, wenn die Transaktion zurückgesetzt oder geschlossen wird). Wie kann ich das umsetzen?

Antwort

2

Sie können für die Sitzung after_commit Ereignis hören mit once=True:

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

Wenn Sie erwarten, Rollback und Wiederverwendung der Sitzung auf der Straße (und nicht der Hörer nach dem Zurückkehren zu feuern), Sie‘ Außerdem müssen Sie das Ereignis im Falle eines Rollback entfernen:

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

Großartig thx, ich lese auch das Dokument über Ereignisse. Ist garantiert, dass entweder after_commit und after_soft_rollback aufgerufen werden (wenn session.close() direkt aufgerufen wird, wird after_soft_rollback ausgelöst?). Und wieso after_soft_rollback statt after_rollback? – jayven

+0

@jayven Ich bin mir ziemlich sicher, dass eine Transaktion entweder festgeschrieben ('after_commit') oder zurückgesetzt (' after_soft_rollback') ist. Der einzige Fall, in dem ich mir nicht sicher bin, ist, ob eine Transaktion noch nicht gestartet wurde, aber das passiert fast nie. 'Session.close' spielt auch keine Rolle, da Sie die Sitzung nach dem Schließen nicht wiederverwenden können (und bei allen neuen Sitzungen, die Sie erstellen, werden die Listener nicht an andere Sitzungen in der Vergangenheit angehängt). Verwenden Sie 'after_soft_rollback', weil es das Ereignis ist, das' session.rollback() 'entspricht; 'after_rollback' entspricht einem SQL' ROLLBACK'. – univerio

+0

Danke für deine Erklärung, das hilft mir sehr. – jayven

Verwandte Themen