455 Stimmen

Spring - @Transactional - Was passiert im Hintergrund?

Ich möchte wissen, was eigentlich passiert, wenn man eine Methode mit @Transactional ? Natürlich weiß ich, dass Spring diese Methode in eine Transaktion verpacken wird.

Ich habe jedoch folgende Zweifel:

  1. Ich habe gehört, dass der Frühling eine Proxy-Klasse ? Kann jemand dies genauer erklären Tiefe . Was befindet sich eigentlich in dieser Proxy-Klasse? Was geschieht mit der eigentlichen Klasse? Und wie kann ich die von Spring erstellte Proxy-Klasse sehen?
  2. Ich habe auch in den Spring-Dokumenten gelesen, dass:

Hinweis: Da dieser Mechanismus auf Proxys basiert, nur "externe" Methodenaufrufe, die über den Proxy eingehen, werden abgefangen . Dies bedeutet, dass ein "Selbstaufruf", d. h. eine Methode innerhalb des Zielobjekts, die eine andere Methode des Zielobjekts aufruft, zur Laufzeit nicht zu einer tatsächlichen Transaktion führt, selbst wenn die aufgerufene Methode mit @Transactional !

Source : http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

Warum fallen nur externe Methodenaufrufe unter Transaktion und nicht die Selbstaufrufmethoden?

325voto

Rob H Punkte 13726

Das ist ein großes Thema. Die Spring-Referenzdokumentation widmet diesem Thema mehrere Kapitel. Ich empfehle die Lektüre der Kapitel über Aspektorientierte Programmierung y Transaktionen da die deklarative Transaktionsunterstützung von Spring auf der Grundlage von AOP basiert.

Aber auf einer sehr hohen Ebene erstellt Spring Proxies für Klassen, die Folgendes deklarieren @Transactional auf die Klasse selbst oder auf Mitglieder. Der Proxy ist zur Laufzeit meist unsichtbar. Er bietet Spring die Möglichkeit, Verhaltensweisen vor, nach oder um Methodenaufrufe herum in das Proxy-Objekt zu integrieren. Die Transaktionsverwaltung ist nur ein Beispiel für die Verhaltensweisen, die eingebunden werden können. Sicherheitsprüfungen sind ein weiteres. Und Sie können auch Ihre eigenen Verhaltensweisen für Dinge wie die Protokollierung bereitstellen. Wenn Sie also eine Methode mit @Transactional erstellt Spring dynamisch einen Proxy, der die gleiche(n) Schnittstelle(n) wie die Klasse implementiert, die Sie annotieren. Wenn Clients Ihr Objekt aufrufen, werden die Aufrufe abgefangen und die Verhaltensweisen über den Proxy-Mechanismus injiziert.

Transaktionen in EJB funktionieren übrigens ganz ähnlich.

Wie Sie festgestellt haben, funktioniert der Proxy-Mechanismus nur, wenn der Aufruf von einem externen Objekt kommt. Wenn Sie einen internen Aufruf innerhalb des Objekts machen, machen Sie wirklich einen Aufruf durch die this Referenz, wodurch der Proxy umgangen wird. Es gibt jedoch Möglichkeiten, dieses Problem zu umgehen. Ich erkläre einen Ansatz in dieser Forumsbeitrag in dem ich eine BeanFactoryPostProcessor um zur Laufzeit eine Instanz des Proxys in "selbstreferenzierende" Klassen zu injizieren. Ich speichere diese Referenz in einer Mitgliedsvariablen namens me . Wenn ich dann interne Aufrufe machen muss, die eine Änderung des Transaktionsstatus des Threads erfordern, leite ich den Aufruf über den Proxy (z. B. me.someMethod() .) Der Forumsbeitrag erklärt dies genauer.

Beachten Sie, dass die BeanFactoryPostProcessor Code wäre jetzt ein wenig anders, wie es zurück in der Spring 1.x Zeitrahmen geschrieben wurde. Aber hoffentlich gibt es Ihnen eine Idee. Ich habe eine aktualisierte Version, die ich wahrscheinlich zur Verfügung stellen könnte.

246voto

skaffman Punkte 389758

Wenn Spring Ihre Bean-Definitionen lädt und so konfiguriert wurde, dass es nach @Transactional Annotationen, wird es diese erstellen Proxy-Objekte um Ihre aktuelle Bohne . Diese Proxy-Objekte sind Instanzen von Klassen, die zur Laufzeit automatisch generiert werden. Das Standardverhalten dieser Proxy-Objekte beim Aufruf einer Methode besteht darin, die gleiche Methode auf der "Ziel"-Bean (d. h. Ihrer Bean) aufzurufen.

Die Proxies können jedoch auch mit Interceptoren versehen werden, und wenn diese vorhanden sind, werden sie vom Proxy aufgerufen, bevor er die Methode der Zielbean aufruft. Für Ziel-Beans, die annotiert sind mit @Transactional wird Spring eine TransactionInterceptor und übergeben es an das generierte Proxy-Objekt. Wenn Sie also die Methode vom Client-Code aus aufrufen, rufen Sie die Methode im Proxy-Objekt auf, das zuerst die TransactionInterceptor (die eine Transaktion startet), die wiederum die Methode auf Ihrer Ziel-Bean aufruft. Wenn der Aufruf beendet ist, wird die TransactionInterceptor die Transaktion festschreibt/zurückrollt. Das ist für den Client-Code transparent.

Was die Sache mit der "externen Methode" angeht, so wird Ihre Bean, wenn sie eine ihrer eigenen Methoden aufruft, dies nicht über den Proxy tun. Denken Sie daran, dass Spring Ihre Bean in den Proxy einhüllt, Ihre Bean hat keine Kenntnis davon. Nur Aufrufe von "außerhalb" Ihrer Bean gehen durch den Proxy.

Ist das hilfreich?

75voto

progonkpa Punkte 2931

Als visueller Mensch möchte ich mich mit einem Sequenzdiagramm des Proxy-Musters einbringen. Wenn Sie nicht wissen, wie die Pfeile zu lesen sind, lese ich den ersten so: Client führt aus. Proxy.method() .

  1. Der Client ruft aus seiner Perspektive eine Methode auf dem Ziel auf und wird vom Proxy unbemerkt abgefangen
  2. Wenn ein Vorher-Aspekt definiert ist, führt der Proxy ihn aus
  3. Dann wird die eigentliche Methode (Ziel) ausgeführt
  4. Die Aspekte "nach dem Zurückgeben" und "nach dem Werfen" sind fakultativ und werden ausgeführt werden, nachdem die Methode zurückkehrt und/oder wenn die Methode eine Ausnahme auslöst
  5. Danach führt der Proxy den After-Aspekt aus (falls definiert)
  6. Schließlich kehrt der Proxy zum aufrufenden Client zurück

Proxy Pattern Sequence Diagram (Ich durfte das Foto unter der Bedingung veröffentlichen, dass ich seine Herkunft nenne. Autor: Noel Vaes, Website: https://www.noelvaes.eu )

70voto

RoshanKumar Mutha Punkte 1885

Die einfachste Antwort ist:

Bei jeder Methode, die Sie deklarieren @Transactional die Begrenzung der Transaktion beginnt und die Begrenzung endet, wenn die Methode abgeschlossen ist.

Wenn Sie einen JPA-Aufruf verwenden, dann alle Übertragungen liegen innerhalb dieser Transaktionsgrenze .

Angenommen, Sie speichern Entität1, Entität2 und Entität3. Während des Speicherns von Entity3 wird nun ein Ausnahme auftreten Da Entity1 und Entity2 in derselben Transaktion sind, werden Entity1 und Entity2 zu Rollback mit entity3.

Transaktion :

  1. entity1.save
  2. entity2.save
  3. entity3.save

Jede Ausnahme führt zu einem Rollback aller JPA-Transaktionen mit der DB. Intern werden JPA-Transaktionen von Spring verwendet.

20voto

Marco Behler Punkte 3127

Alle vorhandenen Antworten sind richtig, aber ich fühle mich nicht in der Lage, gerade dieses komplexe Thema zu geben.

Eine umfassende, praktische Erklärung finden Sie in diesem Dokument Spring @Transactional In-Depth Leitfaden, der versucht, die Transaktionsverwaltung in ~4000 einfachen Worten und mit vielen Codebeispielen zu behandeln.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X