2012-03-29 7 views
14

Ich habe eine Reihe von @Service Beans, die Kernfunktionalität von einer abstrakten Klasse erben. Ich habe jeden der konkreten Sub-Class-Dienste mit @Service und @Transactional markiert. Die abstrakte Superklasse enthält die Methode des öffentlichen Einstiegspunkts für jeden dieser Dienste. Mit anderen Worten, ich habe etwas Ähnliches wie die folgenden:Spring @Transactional Vererbungsregeln

abstract class AbstractService { 

    public void process() { 
     // Do common initialisation code here 
     processSpecific(); 
     // Do common completion code here 
    } 

    abstract protected void processSpecific(); 
} 


@Service @Transactional 
public class FirstSpecificService extends AbstractService { 
    protected void processSpecific() { 
     // Do specific processing code here 
    } 
} 


@Service @Transactional 
public class SecondSpecificService extends AbstractService { 
    protected void processSpecific() { 
     // Do different specific processing code here 
    } 
} 

Der spezifische Code in jedem konkreten Unterklasse-Service macht mehrere Anrufe auf die DAO-Schicht, um Änderungen an der Datenbank vornehmen, die REQUIRED als Transaktions Ausbreitung haben Art.

Jetzt mit den oben definierten Diensten, entdeckte ich, dass es keine aktuelle Transaktion in einem der Code dieser konkreten Unterklasse-Dienste gab, und jeder Aufruf der DAO-Ebene erstellte eine neue Transaktion, die Änderungen vorgenommen, die Transaktion begehen und zurückgeben.

Allerdings, wenn ich die abstrakte Superklasse mit @Transactional mit Anmerkungen versehen, dann eine Transaktion ist ordnungsgemäß erstellt, und die Unter Anrufe an die DAO-Schicht alle beteiligen sich an der aktuellen Transaktion.

Also meine Frage ist, was sind die Regeln für die Übernahme der @Transactional Verhalten? Warum verwendet Spring nicht die @Transactional für die konkreten Sub-Class-Dienste, die es tatsächlich instanziiert? Muss die @Transactional in diesem Fall auf der Super-Klasse sein, weil das die öffentliche Einstiegspunkt-Methode ist?

+0

Übrigens, ich habe mir die [relevante SpringSource-Dokumentation] (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework) angesehen -reference.html # transaction-declarative-annotations), aber das scheint dies nicht zu erfassen. – DuncanKinnear

Antwort

9

Vom Frühjahr Transaktionsdokumentation,

Hinweis: Im Proxy-Modus (die Standardeinstellung), nur ‚externe‘ Methode in über den Proxy abgefangen werden Anrufe kommen. Dies bedeutet, dass "Self-Invocation", d. H. Eine Methode innerhalb des Zielobjekts, die eine andere Methode des Zielobjekts aufruft, nicht zur tatsächlichen Transaktion zur Laufzeit führt, auch wenn die aufgerufene Methode mit @Transactional markiert ist!

Auch wenn Sie die @Transactional auf Ihre konkrete Umsetzung und Sie Prozess-Methode aufrufen, die tatsächlich durch Ihre Anmerkung Transaktions-, aber der Prozess Methode processSpecific auf Ihre Unter Klasse aufrufen wird nicht wegen dieser internen Anruf transaktional.

Schauen Sie in Weben.

+0

Aber wird der Proxy nicht eine Instanz von 'FirstSpecificService' sein? In diesem Fall ruft das System die externe "Prozess" -Methode dieser Instanz auf und die Instanz selbst wird als "@ Transactional" markiert. Ich verstehe vollständig, dass interne private oder geschützte Methoden, die als "@ Transactional" gekennzeichnet sind, die Transaktion nicht beeinflussen, aber das ist nicht das, was ich habe. Meine gesamte Bean ist als '@ Transactional' markiert. – DuncanKinnear

+0

Nein, es wird nicht transaktional sein, wenn es von der internen Methode aufgerufen wird. Wenn Sie die Prozessmethode von extern aufrufen, wird die Proxy-Instanz transaktionsgesteuert. Wenn die Prozessmethode processSpecific aufruft, weiß spring nichts über die Transaktion, da die Punktausblendung im Proxy-Objekt und nicht in der Unterklasse processSpecific erfolgte Methode. Wir hatten das gleiche Problem und wir haben Ladezeit Weben hinzugefügt und alles hat funktioniert. – Kathir

+0

Cab erklären Sie "Ladezeit Weben" in Bezug auf mein Beispiel oben. Wie würde es den Code dieser (konstruierten) Beispieldienste ändern? – DuncanKinnear

1

Haben Sie den Teil über transaction propagation gelesen und wie er mit @Transactional konfiguriert werden kann?

Ein weiterer Bereich von Interesse ist, dass Spring empfiehlt, dass Sie annotate concrete classes (als Gegensatz zu annotieren Schnittstellen).

+0

Ja, wie oben erwähnt, habe ich alle diese Abschnitte der Dokumentation gelesen und nichts davon scheint in diesem Fall zu gelten. Meine abstrakte Superklasse ist ** nicht ** eine Schnittstelle, es ist Code, der von der konkreten Unterklasse geerbt wird. Vielleicht könnten Sie den Abschnitt der Dokumentation zitieren, der Ihrer Meinung nach auf mein Beispiel zutrifft. – DuncanKinnear

+1

Wenn Sie sicherstellen möchten, dass Ihre DAOs immer an einer bestehenden Transaktion teilnehmen (die von Ihrem Dienst initiiert wurde), sollten Sie die DAOs als @Transactional konfigurieren (propagation = [Propagation.MANDATORY] (http://static.springsource.org) /spring/docs/3.1.x/javadoc-api/org/springframework/transaction/annotation/Propagation.html#MANDATORY)), weil mit [REQUIRED] (http://static.springsource.org/spring/docs/3.1 .x/javadoc-api/org/Springframework/Transaktion/Annotation/Propagation.html # REQUIRED) erstellt eine neue Transaktion, wenn keine existiert. – matsev

+0

Ja, das wäre ein Weg für uns, diese Probleme in Zukunft zu erfassen, aber es erklärt immer noch nicht, was die Vererbungsregeln sind. – DuncanKinnear

Verwandte Themen