2012-03-29 9 views
14

Ho un set di bean @Service che ereditano funzionalità di base da una classe astratta. Ho contrassegnato ciascuno dei servizi di sottoclasse concreti con @Service e @Transactional. La super classe astratta contiene il metodo del punto di ingresso pubblico per ciascuno di questi servizi. In altre parole, ho qualcosa simile al seguente:Spring @Transferimenti ereditarietà

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 
    } 
} 

Il codice specifica in ogni servizio sottoclasse concreta rende più chiamate allo strato DAO di apportare modifiche al database, che hanno REQUIRED come la propagazione transazionale genere.

Ora con i servizi definiti come sopra, ho scoperto che non c'era nessuna transazione corrente all'interno di alcun codice di questi servizi di sottoclasse concreti, e ogni chiamata al livello DAO stava creando una nuova transazione, facendo le modifiche, commettendo la transazione e tornando.

Tuttavia, se annotare l'astratto super-classe con @Transactional, poi una transazione è creato correttamente, e le sub-chiamate verso lo strato DAO tutti partecipano alla transazione corrente.

Quindi la mia domanda è: quali sono le regole per ereditare il comportamento di @Transactional? Perché Spring non usa lo @Transactional sui servizi di sottoclasse concreti che sta effettivamente creando? Il @Transactional deve essere sulla super-classe in questo caso, perché è qui che si trova il metodo del punto di accesso pubblico?

+0

A proposito, ho dato un'occhiata alla [documentazione SpringSource pertinente] (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework -reference.html # transaction-declarative-annotations), ma questo non sembra coprire questo. – DuncanKinnear

risposta

9

Dalla documentazione relativa all'operazione di primavera,

Nota: In modalità proxy (che è il default), unico metodo 'esterna' chiamate in arrivo attraverso il proxy verrà intercettato. Ciò significa che 'autoinvocazione', ovvero un metodo all'interno dell'oggetto target che chiama un altro metodo dell'oggetto dell'oggetto target, non porterà a una transazione effettiva in fase di esecuzione anche se il metodo richiamato è contrassegnato con @Transactional!

Anche se avete la @Transactional sulla concreta attuazione e che si sta chiamando il metodo processo che è in realtà transazionale l'annotazione, ma il metodo processo chiamando processSpecific sulla tua classe sub non è transazionale a causa di questa chiamata interna.

Guardare nella tessitura.

+0

Ma il proxy non sarà un'istanza di "FirstSpecificService"? In tal caso, il sistema chiamerà il metodo "processo" esterno di quell'istanza e l'istanza stessa verrà contrassegnata come "@ Transactional". Comprendo perfettamente che i metodi interni privati ​​o protetti contrassegnati come '@ Transactional' non influenzeranno la transazione, ma non è quello che ho. Il mio intero bean è contrassegnato come '@ Transactional'. – DuncanKinnear

+0

No, non sarà transazionale se è chiamato dal metodo interno. Per iniziare quando si chiama il metodo di processo da esterno, l'istanza proxy è controllata dalla transazione e quando il metodo di processo chiama processSpecific, spring non conosce il transactional come è stato fatto il taglio di punto sull'oggetto proxy non sul processo sub-classSpecific metodo. Abbiamo avuto lo stesso problema e abbiamo aggiunto la tessitura del tempo di caricamento e tutto ha funzionato. – Kathir

+0

Cab che spieghi 'tempo di carico tessere' rispetto al mio esempio sopra. Come cambierebbe il codice di questi servizi di esempio (inventati)? – DuncanKinnear

1

Hai letto la parte su transaction propagation e come può essere configurata utilizzando @Transactional?

Un'altra area di interesse è che Spring consiglia di eseguire annotate concrete classes (anziché annotare le interfacce).

+0

Sì, come indicato sopra, ho letto tutte le sezioni della documentazione e nessuna di queste sembra essere applicabile in questo caso. La mia super-classe astratta è ** non ** un'interfaccia, è un codice ereditato dalla sottoclasse concreta attuale. Forse potresti citare la sezione della documentazione che ritieni applicabile al mio esempio. – DuncanKinnear

+1

Se si desidera assicurarsi che i DAO partecipino sempre a una transazione esistente (avviata dal servizio), è necessario configurare i DAO come @Transactional (propagation = [Propagation.MANDATORY] (http://static.springsource.org /spring/docs/3.1.x/javadoc-api/org/springframework/transaction/annotation/Propagation.html#MANDATORY)), perché si utilizza [REQUIRED] (http://static.springsource.org/spring/docs/3.1 .x/javadoc-api/org/springframework/transaction/annotation/Propagation.html # REQUIRED) creerà una nuova transazione se non esiste. – matsev

+0

Sì, sarebbe un modo per noi di cogliere questi problemi in futuro, ma non spiega ancora quali siano le regole di ereditarietà. – DuncanKinnear