2016-03-22 19 views
0

Die Frage, die ich heute habe, ist, wie man eine Methode erneut versucht, nachdem die @Transactional Annotation eine OLE (Optimistic Lock Exception) verursacht und die Transaktion rückgängig macht.Abfangen von @Transactional Nach optimistischer Sperre für asynchrone Aufrufe in Restful App

Ich habe asynchrone Aufrufe an eine Restful-Anwendung, die versuchen, ein Datenbankobjekt basierend auf einer Geschäftslogik zu aktualisieren. Wenn ich ein OLE bekomme, möchte ich die Transaktion nach einer Verzögerung von 0.2-0.5 Sekunden wiederholen.

Ich habe versucht, AspectJ meine Methode abzufangen, nachdem es das OLE wirft, so dass ich es erneut versuchen kann. Das Problem ist jedoch die @ Transactional Annotation. Meine Methode ist nicht Werfen der Fehlermeldung seit Geschäftslogik nicht fehlschlägt. Stattdessen gibt myMethod eine 200-Antwort zurück, aber die OLE-Ausnahme tritt auf und wird dann in die ResourceJavaMethodDispatcher.java-Klasse geworfen, die für das Aufrufen von myMethod verantwortlich ist.

My Aspekt Klasse:

@Aspect 
public class myAspect { 

    @AfterThrowing(value = "execution(* com.package.blah.myClass.myMethod(..)) && args(.., myParam)", throwing = "ex") 
    public Response catchAndRetry(JoinPoint jp, Throwable ex, Long myParam) throws Throwable { 

     Response response = null; 

     response = invokeAndRetry(jp, myParam); 

     return response; 
    } 
} 

Die invokeAndRetry() Methode weist die Logik auf dem Thread warten zu rufen, und dann auf ein Maximum von drei Versuchen erneut versuchen auf.

Ich kann erfolgreich in myAspect aus einer Ausnahme von Business-Logik geworfen werden; aber das OLE, das von der Transaktion geworfen wird, wird in myAspect nicht gefangen.

Nachdem all dies gesagt wurde, gibt es eine Möglichkeit, die @Transaction-Annotation zu umbrechen/einzukapseln/abzufangen, um meine Wiederholungslogik auszuführen?

Side Hinweise:

1) Ich habe meine eigene @Retry Annotation in der Schaffung sieht am Beispiel here. Ich habe diese Abhängigkeit verwendet, um seine @ Retry-Annotation zu versuchen, aber ohne Erfolg.

2) Ich werde in Spring @ within nachsehen, ob das nützlich sein könnte.

Antwort

0

Nachdem ich einige Nachforschungen angestellt und einige Tutorials angeschaut habe, habe ich einen Weg gefunden, meinen Aspekt gegenüber @Transactional Vorrang zu haben. Direkt unter dem @ Aspect-Tag habe ich die Annotation @Order (1) hinzugefügt.

Dies gibt meinem Aspekt höhere Priorität, da @Transactional auf Ordered.LOWEST_PRECEDENCE gesetzt ist. Weitere Details zu @Order finden Sie unter Spring documentation.

0

Die kurze Antwort ist: Sie sollten nicht versuchen, eine EntityManager wieder zu verwenden, nachdem eine Ausnahme auftritt. Nach dem Hibernate EntityManager User guide on Transactions and concurrency, die höchstwahrscheinlich für alle PPV-Anbieter gilt:

Wenn die EntityManager eine Ausnahme (einschließlich SQLException) wirft, sollten Sie sofort die Datenbank Transaktion Rollback, rufen EntityManager.close() (wenn createEntityManager() aufgerufen wurde) und verwerfen Sie die EntityManager Instanz. Bestimmte Methoden von EntityManager lassen den Persistenzkontext nicht in einem konsistenten Zustand. Keine Ausnahme, die von einem Entitätsmanager ausgelöst wird, kann als wiederherstellbar behandelt werden. Stellen Sie sicher, dass die EntityManager durch Aufruf von close() in einem finally-Block geschlossen wird. Beachten Sie, dass ein Container-verwalteter Entitätsmanager dies für Sie erledigt. Sie müssen nur die RuntimeException bis zum Container propagieren lassen.

Sie könnten in der Lage, die wiederholen Sie den Vorgang in einer neuen Transaktion mit einer neuen Instanz eineine EntityManager obwohl zu tun, aber das ist ein anderer Anwendungsfall.