Metodo @Transactional che chiama un altro metodo senza annotazione @Transactional?


89

Ho visto un metodo in una classe Service che era contrassegnato come @Transactional, ma chiamava anche altri metodi nella stessa classe che non erano contrassegnati come @Transactional.

Significa che la chiamata a metodi separati fa sì che l'applicazione apra connessioni separate al DB o sospenda la transazione padre, ecc.?

Qual è il comportamento predefinito per un metodo senza annotazioni che viene chiamato da un altro metodo con @Transactionalannotazione?

Risposte:


119

Quando chiami un metodo senza @Transactionalall'interno di un blocco di transazione, la transazione principale continuerà con il nuovo metodo. Utilizzerà la stessa connessione dal metodo padre (con @Transactional) e qualsiasi eccezione causata nel metodo chiamato (senza @Transactionalcauserà il rollback della transazione come configurato nella definizione della transazione.

Se chiami un metodo con @Transactionalun'annotazione da un metodo @Transactionalall'interno della stessa istanza, il comportamento transazionale dei metodi chiamati non avrà alcun impatto sulla transazione. Ma se si chiama un metodo con una definizione di transazione da un altro metodo con una definizione di transazione e si trovano in istanze diverse, il codice nel metodo chiamato seguirà le definizioni di transazione fornite nel metodo chiamato.

È possibile trovare ulteriori dettagli nella sezione Gestione delle transazioni dichiarative della documentazione delle transazioni primaverili .

Il modello di transazione dichiarativa Spring utilizza il proxy AOP. quindi il proxy AOP è responsabile della creazione delle transazioni. Il proxy AOP sarà attivo solo se i metodi con nell'istanza vengono chiamati dall'esterno dell'istanza.


è questo il comportamento predefinito della molla?
goe

Sì. È il comportamento predefinito.
Arun P Johny

2
@Tomasz Sì. Ma va anche detto che la modifica della propagazione delle transazioni su un metodo chiamato da un altro metodo @Transactional non avrà alcun effetto.
Fil

1
@ Tomasz, era quello che volevo dire will follow the transaction definitions given in the called method. Ma se la chiamata proviene dalla stessa istanza dell'oggetto, non avrà alcun effetto poiché la chiamata non si propagherà attraverso i proxy aop responsabili della manutenzione della transazione.
Arun P Johny

5
@Filip, Questo non è completamente corretto, Se chiami un metodo con una @Transactionaldefinizione da un oggetto / istanza diverso, anche se il metodo chiamante ha @Transactionalattributi diversi , il metodo chiamato seguirà la sua definizione di transazione.
Arun P Johny

24
  • Ciò significa che la chiamata a metodi separati fa sì che l'applicazione apra connessioni separate al DB o sospenda la transazione padre, ecc.?

Dipende dal livello di propagazione . Ecco tutti i possibili valori di livello .

Ad esempio, nel caso in cui un livello di propagazione sia NIDATO, una transazione corrente verrà "sospesa" e verrà creata una nuova transazione ( nota: la creazione effettiva di una transazione annidata funzionerà solo su gestori di transazioni specifici )

  • Qual è il comportamento predefinito per un metodo senza annotazioni chiamato da un altro metodo con l'annotazione @Transactional?

Il livello di propagazione predefinito (ciò che chiamate "comportamento") è RICHIESTO . Nel caso in cui venga chiamato un metodo "interno" che ha @Transactionalun'annotazione su di esso (o transato in modo dichiarativo tramite XML), verrà eseguito all'interno della stessa transazione , ad esempio "niente di nuovo" viene creato.


E le chiamate secondarie di NOT_SUPPORTED che non hanno alcuna annotazione? Eredita NOT_Supported o hanno aperto una nuova transazione poiché REQURED è l'impostazione predefinita? Ad esempio: f1.call () {f2 ()} con l'annotazione NOT_SUPPORTED per f1 e non per f2.
Dave

8

@Transactional segna il limite della transazione (inizio / fine) ma la transazione stessa è vincolata al thread. Una volta avviata una transazione, si propaga attraverso le chiamate al metodo finché il metodo originale non ritorna e la transazione esegue il commit / rollback.

Se viene chiamato un altro metodo che ha un'annotazione @Transactional, la propagazione dipende dall'attributo di propagazione di tale annotazione.


Le 3 risposte sono in qualche modo in conflitto tra loro, non sono sicuro quale sia più accurata.
Trump 2020 - La giustizia arriverà il

1
@EricWang Volevo solo condividere che ho testato questo scenario oggi e la risposta di Arun P Johny (con commenti) è la più accurata per questo scenario di invocazioni interne .
Vinay Vissh,

3

Il metodo interno influenzerà il metodo esterno se il metodo interno non è annotato con @Transactional.

Nel caso in cui il metodo interno sia annotato anche con @Transactional con REQUIRES_NEW, succederà quanto segue.

...
@Autowired
private TestDAO testDAO;

@Autowired
private SomeBean someBean;

@Override
@Transactional(propagation=Propagation.REQUIRED)
public void outerMethod(User user) {
  testDAO.insertUser(user);
  try{
    someBean.innerMethod();
  } catch(RuntimeException e){
    // handle exception
  }
}


@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void innerMethod() {
  throw new RuntimeException("Rollback this transaction!");
}

Il metodo interno viene annotato con REQUIRES_NEWe genera un'eccezione RuntimeException, quindi imposterà la sua transazione su rollback ma NON EFFETTUERÀ la transazione esterna. La transazione esterna viene IN PAUSA all'avvio della transazione interna e quindi RIPRENDE DOPO la conclusione della transazione interna. Funzionano indipendentemente l'uno dall'altro, quindi la transazione esterna PU essere eseguita correttamente.


1
Per chiarire ai principianti, sono abbastanza sicuro che innerMethod () deve trovarsi su un bean diverso (noto anche come Oggetto java gestito da Spring) rispetto a outerMethod (). Se sono entrambi sullo stesso bean, non credo che innerMethod utilizzerà effettivamente il comportamento Transactional dichiarato nella sua annotazione. Piuttosto userà ciò che è dichiarato nella dichiarazione outerMethod (). Ciò è dovuto al modo in cui Spring gestisce AOP, che viene utilizzato per le sue annotazioni @Transactional ( docs.spring.io/spring/docs/3.0.x/spring-framework-reference/… )
johnsimer
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.