2011-11-09 13 views
7

Ho una classe @Service che ha un metodo @Transactional che chiama un altro metodo @Transactional sulla stessa classe. Stavo testando il comportamento del rollback per questo e ho scoperto che non funzionava correttamente. Il codice simile a questa:Spring nested @Transactional method and rollback

@Service 
public class DefaulService implements ervice 
{ 
    @Transactional 
    public void methodOne() 
    { 
     methodTwo(); 

      //question edited 
      //this seems to be the problem 
      this.serviceDAO.executeUpdateOperation(); 

     //test rollback 
     throw new RuntimeException(); 
    } 

    @Transactional 
    public void methodTwo() 
    { 
     //DAO stuff 
    } 
} 

Dopo l'esecuzione methodOne controllo il database e le modifiche sono lì, anche se il registro mostra "JDBCTransaction - rollback".

Se chiamo methodDue singolarmente e aggiungo un'eccezione alla fine, le modifiche vengono ripristinate correttamente.

C'è un modo per rendere methodOne correttamente le modifiche di rollback che si sono verificate durante la chiamata @Transactional nidificata? Avevo l'impressione che la propagazione predefinita di REQUIRED avrebbe raggiunto questo obiettivo, ma non sembra funzionare. Grazie

UPDATE

Ok, ho appena notato qualcosa di diverso. Proprio prima del lancio dell'eccezione, sto chiamando il dao del servizio e sto eseguendo un aggiornamento manuale tramite 'executeUpdate'. Se commento questa riga, il rollback annidato funziona. Sembra quindi che il problema sia in realtà chiamare DAO ed eseguire query executeUpdate. Ma non dovrebbe funzionare anche all'interno della transazione corrente?

+0

Sei consapevole del fatto che quando si chiama 'methodTwo()' da 'methodOne() 'l'annotazione' @ Transactional' su quella precedente viene ignorata? Vedi il mio [articolo] (http://nurkiewicz.blogspot.com/2011/10/spring-pitfalls-proxying.html) per ulteriori dettagli. Tuttavia questo non causa i tuoi problemi, ma vale la pena di saperlo. –

+0

Sì, ma poiché MethodTwo può essere chiamato in modo indipendente, quindi ha bisogno della propria annotazione per tali casi. In questo momento sono perplesso sul motivo per cui executeUpdate causa il commit della transazione, anche se forse questo è il comportamento predefinito. – JayPea

+1

qual è la propagazione della transazione del servizio a pagamento? È per caso REQUIRES_NEW? – Hendrik

risposta

1

Si sta sicuramente ottenendo l'istanza del "servizio" dal bean factory quando si chiamano i metodi, giusto? Il bean factory deve impostare un proxy che implementa la logica transazionale attorno a ciascuna chiamata di metodo. Avevo l'impressione che questo funzionasse solo quando "estranei" invocavano metodi tramite il proxy e non necessariamente funzionano quando un metodo chiama un altro, poiché tale metodo è una chiamata diretta all'interno dell'oggetto di implementazione e non passa attraverso il proxy AOP.

+0

Dipende dal tipo di approccio AOP che si sta utilizzando. Controlla il [link] (http://nurkiewicz.blogspot.com/2011/10/spring-pitfalls-proxying.html) da Tomasz Nurkiewicz. Inoltre, questo non può spiegare il comportamento che JayPea sta descrivendo. –

Problemi correlati