2010-06-25 13 views

risposta

83

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

La raccomandazione della squadra Primavera è che si annotare solo classi concrete con l'@Transactional annotazione, al contrario di annotare le interfacce. È possibile posizionare l'annotazione @Transactional su un'interfaccia (o un metodo di interfaccia), ma funziona solo come ci si aspetterebbe se si utilizzano proxy basati su interfaccia. Il fatto che le annotazioni siano non ereditate significa che se si utilizzano i proxy basati sulla classe, le impostazioni della transazione non verranno riconosciute dall'infrastruttura proxy basata sulla classe e l'oggetto non verrà incapsulato in un proxy transazionale (che sarebbe decisamente difettoso). Quindi, per favore, prendi il consiglio del team di Spring e annota solo le lezioni concrete (e i metodi delle classi concrete) con l'annotazione @Transactional.

Nota: poiché questo meccanismo è basato su proxy, verranno intercettate solo chiamate di metodo "esterne" che arrivano attraverso il proxy. Ciò significa che "autoinvocazione", ovvero un metodo all'interno dell'oggetto target che chiama un altro metodo dell'oggetto target, non porterà a una transazione effettiva in fase di esecuzione anche se il metodo richiamato è contrassegnato con @Transactional!

(enfasi aggiunta alla prima frase, altra enfasi dall'originale.)

+0

Big +1 BTW, mi sono preso la libertà di rendere la citazione una citazione, quindi le persone non sono confuse e hanno aggiunto il corsivo e tale dall'originale. –

+0

@ T.J. Crowder - Incredibile come cambiano le altre risposte. thx, NP –

+0

Ho già letto questa dichiarazione prima in Spring docu, ma ancora non riesco a capire perché le impostazioni _transaction non verranno riconosciute dall'infrastruttura proxy_ basata sulla classe? Personalmente, penso che si tratti solo della limitazione dell'implementazione di Spring, non del problema dell'infrastruttura proxy sottostante. –

0

Mettere sull'interfaccia è bene finché tutti gli implementatori prevedibili di vostra cura IFC sui dati TX (operazioni non sono problemi che solo i database gestiscono). Se il metodo non interessa TX (ma devi metterlo lì per Hibernate o qualsiasi altra cosa), mettilo sull'imp.

Inoltre, potrebbe essere un po 'meglio mettere @Transactional sui metodi nell'interfaccia:

public interface FooService { 
    @Transactional(readOnly = true) 
    void doSmth(); 
} 
7

Si possono mettere sul interfaccia, ma essere in guardia che le transazioni non possono finire accadendo in alcuni casi. Vedere la seconda punta in Secion 10.5.6 dei documenti di primavera:

Primavera consiglia di annotare solo classi concrete (e metodi di classi concrete) con l'annotazione @Transactional, al contrario di annotare le interfacce. È certamente possibile posizionare l'annotazione @Transactional su un'interfaccia (o un metodo di interfaccia), ma funziona solo come ci si aspetterebbe se si utilizzano proxy basati su interfaccia. Il fatto che le annotazioni Java non siano ereditate dalle interfacce significa che se si utilizzano i proxy basati sulla classe (proxy-target-class = "true") o l'aspetto basato sulla tessitura (mode = "aspectj"), allora le impostazioni della transazione sono non riconosciuto dall'infrastruttura di proxy e tessitura, e l'oggetto non verrà incapsulato in un proxy transazionale, il che sarebbe decisamente negativo.

Suggerirei di metterli sull'implementazione per questo motivo.

Inoltre, per me le transazioni sembrano un dettaglio di implementazione, quindi dovrebbero essere nella classe di implementazione. Immagina di avere implementazioni di wrapper per la registrazione o le implementazioni di test (mock) che non devono necessariamente essere transazionali.

6

di primavera recommendation è che di annotare le implementazioni concrete invece di un'interfaccia. Non è errato usare l'annotazione su un'interfaccia, è solo possibile abusare di quella funzione e bypassare inavvertitamente la dichiarazione @Transaction.

Se hai contrassegnato qualcosa di transazionale in un'interfaccia e poi fai riferimento a una delle sue classi di implementazione altrove in primavera, non è del tutto ovvio che l'oggetto creato da Spring non rispetterà l'annotazione @Transactional.

In pratica sembra qualcosa di simile:

public class MyClass implements MyInterface { 

    private int x; 

    public void doSomethingNonTx() {} 

    @Transactional 
    public void toSomethingTx() {} 

} 
2

Sostenere @Transactional sulle classi di calcestruzzo:

Preferisco architettare una soluzione in 3 sezioni in generale: un'API, un Im plementation e un Web (se necessario). Faccio del mio meglio per mantenere l'API come leggera/semplice/POJO il più possibile riducendo al minimo le dipendenze. È particolarmente importante se la giochi in un ambiente distribuito/integrato in cui devi condividere molto le API.

Mettere @Transactional richiede le librerie Spring nella sezione API, che IMHO non è efficace. Quindi preferisco aggiungerlo nell'implementazione in cui è in esecuzione la transazione.

Problemi correlati