Spring – @Transactional – Was passiert im Hintergrund?

Lesezeit: 9 Minuten

Spring @Transactional Was passiert im Hintergrund
Spitze

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

Aber ich habe folgende Zweifel:

  1. Ich habe gehört, dass der Frühling a erstellt Proxy-Klasse? Kann jemand das näher erläutern Tiefe. Was befindet sich eigentlich in dieser Proxy-Klasse? Was passiert mit der eigentlichen Klasse? Und wie kann ich die von Spring erstellte Proxy-Klasse sehen?
  2. Ich habe auch in Spring docs gelesen, dass:

Hinweis: Da dieser Mechanismus auf Proxys basiert, nur „externe“ Methodenaufrufe, die über den Proxy eingehen, werden abgefangen. Dies bedeutet, dass ein „Selbstaufruf“, dh 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 gekennzeichnet ist @Transactional!

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

Warum befinden sich nur externe Methodenaufrufe unter Transaction und nicht die Selbstaufrufmethoden?

  • Eine relevante Diskussion finden Sie hier: stackoverflow.com/questions/3120143/…

    – dma_k

    26. September 2010 um 20:07 Uhr

Spring @Transactional Was passiert im Hintergrund
Rob H

Das ist ein großes Thema. Das Spring-Referenzdokument widmet ihm mehrere Kapitel. Ich empfehle, die weiter zu lesen Aspektorientierte Programmierung und Transaktionenda die deklarative Transaktionsunterstützung von Spring AOP als Grundlage verwendet.

Aber auf sehr hohem Niveau erstellt Spring Proxys für deklarierende Klassen @Transactional auf die Klasse selbst oder auf Mitglieder. Der Proxy ist zur Laufzeit meist unsichtbar. Es bietet Spring eine Möglichkeit, Verhaltensweisen vor, nach oder um Methodenaufrufe in das Proxy-Objekt einzufügen. Das Transaktionsmanagement ist nur ein Beispiel für einklinkbare Verhaltensweisen. Sicherheitsüberprüfungen sind ein weiteres. Und Sie können auch Ihre eigenen für Dinge wie Protokollierung bereitstellen. Wenn Sie also eine Methode mit kommentieren @Transactional, erstellt Spring dynamisch einen Proxy, der die gleiche(n) Schnittstelle(n) implementiert wie die Klasse, die Sie annotieren. Und wenn Clients Ihr Objekt aufrufen, werden die Aufrufe abgefangen und das Verhalten über den Proxy-Mechanismus injiziert.

Transaktionen in EJB funktionieren übrigens ähnlich.

Wie Sie bemerkt haben, funktioniert der Proxy-Mechanismus nur, wenn Aufrufe von einem externen Objekt eingehen. Wenn Sie innerhalb des Objekts einen internen Anruf tätigen, tätigen Sie in Wirklichkeit einen Anruf über das this Referenz, die den Proxy umgeht. Es gibt jedoch Möglichkeiten, dieses Problem zu umgehen. Einen Ansatz erläutere ich in diesen Forumsbeitrag in dem ich a verwende BeanFactoryPostProcessor um eine Instanz des Proxys zur Laufzeit in “selbstreferenzierende” Klassen einzufügen. Ich speichere diesen Verweis auf eine Member-Variable namens me. Wenn ich dann interne Anrufe tätigen muss, die eine Änderung des Transaktionsstatus des Threads erfordern, leite ich den Anruf über den Proxy (z me.someMethod().) Der Forenbeitrag erklärt ausführlicher.

Notiere dass der BeanFactoryPostProcessor Der Code wäre jetzt etwas anders, da er im Zeitrahmen von Spring 1.x geschrieben wurde. Aber hoffentlich gibt es Ihnen eine Idee. Ich habe eine aktualisierte Version, die ich wahrscheinlich zur Verfügung stellen könnte.

  • >> Der Proxy ist zur Laufzeit meist unsichtbar Oh !! Ich bin neugierig, sie zu sehen 🙂 Rest.. Ihre Antwort war sehr umfassend. Dies ist das zweite Mal, dass Sie mir helfen. Danke für all die Hilfe.

    – Spitze

    8. Juli 2009 um 17:37 Uhr

  • Kein Problem. Sie können den Proxy-Code sehen, wenn Sie mit einem Debugger durchgehen. Das ist wahrscheinlich der einfachste Weg. Es gibt keine Magie; Sie sind nur Klassen innerhalb der Frühlingspakete.

    – Rob H

    8. Juli 2009 um 17:47 Uhr

  • Und wenn die Methode mit der Annotation @Transaction eine Schnittstelle implementiert, verwendet der Frühling die dynamische Proxy-API, um die Transaktionalisierung einzufügen und nicht Proxys verwenden. Ich ziehe es auf jeden Fall vor, dass meine transaktionalisierten Klassen Schnittstellen implementieren.

    – Michael Willes

    10. Juli 2009 um 14:12 Uhr

  • Ich habe auch das „Ich“-Schema gefunden (mit expliziter Verdrahtung, um es so zu machen, wie es meiner Meinung nach passt), aber ich denke, wenn Sie es so machen, sind Sie wahrscheinlich besser dran, wenn Sie es so umgestalten, dass Sie es nicht tun müssen, zu … haben. Aber ja, das kann manchmal sehr peinlich sein!

    – Donal Fellows

    2. Februar 2013 um 23:31 Uhr

  • 2019: Da diese Antwort veraltet ist, ist der referenzierte Forenbeitrag nicht mehr verfügbar, der den Fall beschreiben würde, wann Sie müssen innerhalb des Objekts einen internen Anruf tätigen ohne unter Umgehung des Proxys, mit BeanFactoryPostProcessor . In dieser Antwort wird jedoch eine (meiner Meinung nach) sehr ähnliche Methode beschrieben: stackoverflow.com/a/11277899/3667003 … und weitere Lösungen im gesamten Thread.

    – Z3d4s

    3. April 2019 um 22:31 Uhr


1646313432 878 Spring @Transactional Was passiert im Hintergrund
Skaffmann

Wenn Spring Ihre Bean-Definitionen lädt und für die Suche konfiguriert wurde @Transactional Anmerkungen, es werden diese erstellt Proxy-Objekte um Ihr tatsächliches Bohne. Diese Proxy-Objekte sind Instanzen von Klassen, die zur Laufzeit automatisch generiert werden. Das Standardverhalten dieser Proxy-Objekte, wenn eine Methode aufgerufen wird, besteht darin, dieselbe Methode auf der “Ziel”-Bean (dh Ihrer Bean) aufzurufen.

Die Proxys können jedoch auch mit Abfangjägern versorgt werden, und wenn vorhanden, werden diese Abfangjäger vom Proxy aufgerufen, bevor er die Methode Ihrer Ziel-Bean aufruft. Für Zielbohnen, die mit annotiert sind @TransactionalSpring wird eine erstellen TransactionInterceptor, und übergeben Sie es an das generierte Proxy-Objekt. Wenn Sie also die Methode aus dem Clientcode aufrufen, rufen Sie die Methode für das Proxy-Objekt auf, das zuerst die aufruft TransactionInterceptor (was eine Transaktion startet), die wiederum die Methode auf Ihrer Ziel-Bean aufruft. Wenn der Aufruf beendet ist, wird die TransactionInterceptor schreibt die Transaktion fest/rollt sie zurück. Es ist für den Client-Code transparent.

Was die “externe Methode” angeht, wenn Ihre Bean eine ihrer eigenen Methoden aufruft, wird dies nicht über den Proxy geschehen. Denken Sie daran, Spring hüllt Ihre Bohne in den Proxy, Ihre Bohne hat keine Kenntnis davon. Nur Anrufe von “außerhalb” Ihrer Bean gehen durch den Proxy.

Hilft das?

  • > Denken Sie daran, dass Spring Ihre Bohne in den Proxy verpackt, Ihre Bohne hat keine Kenntnis davon Das sagte alles. Was für eine tolle Antwort. Danke fürs Helfen.

    – Spitze

    8. Juli 2009 um 17:39 Uhr

  • Großartige Erklärung für den Proxy und die Abfangjäger. Jetzt verstehe ich, dass Spring ein Proxy-Objekt implementiert, um Aufrufe an eine Ziel-Bean abzufangen. Danke!

    – dharag

    20. August 2013 um 15:39 Uhr

  • Ich denke, Sie versuchen, dieses Bild der Spring-Dokumentation zu beschreiben, und dieses Bild zu sehen, hilft mir sehr: docs.spring.io/spring/docs/4.2.x/spring-framework-reference/…

    – WesternGun

    22. November 2018 um 10:33 Uhr


  • ziemlich spät zur Party – These proxy objects are instances of classes that are auto-generated at runtime. wann passiert das genau. Wenn die Anwendung in die JVM geladen wird oder wenn die Bean (die per Proxy verpackt werden sollte) zum ersten Mal aufgerufen wird.

    – Samsher

    21. Oktober 2021 um 9:40 Uhr

1646313432 757 Spring @Transactional Was passiert im Hintergrund
progonkpa

Als visueller Mensch wäge ich gerne mit einem Sequenzdiagramm des Proxy-Musters ab. Wenn Sie nicht wissen, wie man die Pfeile liest, lese ich den ersten so: Client führt aus Proxy.method().

  1. Der Client ruft aus seiner Perspektive eine Methode für das Ziel auf und wird stillschweigend vom Proxy abgefangen
  2. Wenn ein Before-Aspekt definiert ist, führt der Proxy ihn aus
  3. Dann wird die eigentliche Methode (Target) ausgeführt
  4. After-returning und after-throwing sind optionale Aspekte, die ausgeführt werden, nachdem die Methode zurückkehrt und/oder wenn die Methode eine Ausnahme auslöst
  5. Danach führt der Proxy den Nachaspekt aus (falls definiert)
  6. Schließlich kehrt der Proxy zum aufrufenden Client zurück

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

1646313435 555 Spring @Transactional Was passiert im Hintergrund
RoshanKumar Mutha

Die einfachste Antwort lautet:

Auf welche Methode Sie deklarieren @Transactional Die Grenze der Transaktion beginnt und die Grenze endet, wenn die Methode abgeschlossen ist.

Wenn Sie dann JPA-Anruf verwenden alle Commits liegen innerhalb dieser Transaktionsgrenze.

Angenommen, Sie speichern Entität1, Entität2 und Entität3. Jetzt beim Speichern von entity3 an Ausnahme auftretendann, da enitiy1 und entity2 in derselben Transaktion vorkommen, werden auch entity1 und entity2 sein Zurückrollen mit Entität3.

Transaktion:

  1. Entität1.speichern
  2. Entität2.speichern
  3. Entity3.save

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

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

Für eine umfassende, praktische Erklärung möchten Sie vielleicht einen Blick darauf werfen Spring @Transactional In-Depth Leitfaden, der sein Bestes versucht, das Transaktionsmanagement in ~4000 einfachen Wörtern mit vielen Codebeispielen abzudecken.

  • Eine echte Antwort auf eine wirklich komplexe Frage. Außerdem liebe ich deinen Blog einfach. Nicht seine einzige, sondern alle.

    – KnockingHeads

    20. Oktober 2021 um 10:41 Uhr


1646313435 951 Spring @Transactional Was passiert im Hintergrund
Danyal Sandeelo

Es mag spät sein, aber ich bin auf etwas gestoßen, das Ihre Besorgnis in Bezug auf den Proxy erklärt (nur „externe“ Methodenaufrufe, die über den Proxy eingehen, werden abgefangen).

Sie haben beispielsweise eine Klasse, die so aussieht

@Component("mySubordinate")
public class CoreBusinessSubordinate {

    public void doSomethingBig() {
        System.out.println("I did something small");
    }

    public void doSomethingSmall(int x){
        System.out.println("I also do something small but with an int");    
  }
}

und Sie haben einen Aspekt, der so aussieht:

@Component
@Aspect
public class CrossCuttingConcern {

    @Before("execution(* com.intertech.CoreBusinessSubordinate.*(..))")
    public void doCrossCutStuff(){
        System.out.println("Doing the cross cutting concern now");
    }
}

Wenn Sie es so ausführen:

 @Service
public class CoreBusinessKickOff {

    @Autowired
    CoreBusinessSubordinate subordinate;

    // getter/setters

    public void kickOff() {
       System.out.println("I do something big");
       subordinate.doSomethingBig();
       subordinate.doSomethingSmall(4);
   }

}

Ergebnisse des Aufrufs von kickOff über dem oben angegebenen Code.

I do something big
Doing the cross cutting concern now
I did something small
Doing the cross cutting concern now
I also do something small but with an int

aber wenn Sie Ihren Code zu ändern

@Component("mySubordinate")
public class CoreBusinessSubordinate {

    public void doSomethingBig() {
        System.out.println("I did something small");
        doSomethingSmall(4);
    }

    public void doSomethingSmall(int x){
       System.out.println("I also do something small but with an int");    
   }
}


public void kickOff() {
  System.out.println("I do something big");
   subordinate.doSomethingBig();
   //subordinate.doSomethingSmall(4);
}

Sie sehen, die Methode ruft intern eine andere Methode auf, damit sie nicht abgefangen wird und die Ausgabe so aussehen würde:

I do something big
Doing the cross cutting concern now
I did something small
I also do something small but with an int

Sie können dies dadurch umgehen

public void doSomethingBig() {
    System.out.println("I did something small");
    //doSomethingSmall(4);
    ((CoreBusinessSubordinate) AopContext.currentProxy()).doSomethingSmall(4);
}

Codeschnipsel entnommen aus:
https://www.intertech.com/Blog/secrets-of-the-spring-aop-proxy/

  • Eine echte Antwort auf eine wirklich komplexe Frage. Außerdem liebe ich deinen Blog einfach. Nicht seine einzige, sondern alle.

    – KnockingHeads

    20. Oktober 2021 um 10:41 Uhr


923760cookie-checkSpring – @Transactional – Was passiert im Hintergrund?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy