2013-04-04 8 views
12

Il servizio My Grails sta riscontrando un problema in cui un'eccezione ingerita non correlata a una transazione sta causando il rollback della transazione anche quando non è correlata alla persistenza dell'oggetto dominio.Come impedire che le eccezioni causino il rollback della transazione in Grails?

Nel mio servizio ho qualcosa sulla falsariga di

updateSomething(domainObj) { 
    def oldFilename = domainObj.filename 
    def newFilename = getNewFilename() 

    domainObj.filename = newFilename 
    domainObj.save(flush: true) 

    try { 
     cleanUpOldFile(oldFilename) 
    } catch (cleanupException) { 
     // oh well, log and swallow 
    } 
} 

quello che sto vedendo è che quando ho eccezione quando sto pulendo il vecchio file, ho il login e ingoiare, ma ancora causa il rollback della transazione, anche se ho già finito di aggiornare l'oggetto dominio.

Come limitare il completamento della transazione dell'oscilloscopio prima della pulizia o c'è un altro modo per ottenere che l'eccezione di pulizia non causi un rollback?

Solo per la cronaca che sto usando Grails 2.1.1

risposta

26

È possibile utilizzare le annotazioni di fare di più a grana fine di demarcazione delle transazioni. Per impostazione predefinita i servizi sono transazionali e tutti i metodi pubblici sono transazionali. Ma se usi le annotazioni @Transactional, Grails non rende tutto transazionale - hai il controllo completo.

Le eccezioni di runtime attivano automaticamente i rollback, ma le eccezioni verificate no. Anche se Groovy non richiede di rilevare eccezioni controllate, la funzione è una cosa Spring che non conosce la gestione delle eccezioni di Groovy.

Le transazioni vengono implementate avvolgendo l'istanza della classe di servizio in un proxy. Se un'eccezione "fugge" il proxy, indipendentemente dal fatto che sia stato catturato o meno, il rollback sarà già avvenuto.

Quindi avete alcune opzioni. Annota updateSomething come @Transactional ma non annotare cleanUpOldFile:

import org.springframework.transaction.annotation.Transactional 

@Transactional 
def updateSomething(domainObj) { 
... 
} 

def cleanUpOldFile(...) { 
    ... 
} 

È inoltre possibile annotare cleanUpOldFile con una o più eccezioni non controllate che non dovrebbe rollback di una transazione (o in altri casi d'uso eccezioni controllate che dovrebbe), ad esempio

@Transactional(noRollbackFor=[FooException, BarException]) 
def cleanUpOldFile(...) { 
    ... 
} 
+0

Una cosa che non capisco del tutto, il mio blocco di cattura non dovrebbe intercettare tutte le eccezioni, sia in fase di esecuzione sia controllate? Come fa la primavera a sapere che ho qualche eccezione? –

+0

Suppongo che stia notando l'eccezione tra i livelli di servizio, nel mio caso ho avuto un livello di servizio che parlava con un altro. Questa è l'unica cosa che ha senso per me. –

+0

Se tutto ciò che si fa è aggiungere @Transactional (noRollbackFor = [FooException, BarException]) a cleanUpOldFile(), quale effetto ha su ogni altro metodo nella classe? Sono ancora transazionali o no? –

8

Oltre alla risposta @Burt Beckwith s', se si dispone di un servizio in cui proprio non si vuole transazioni (che ho effettivamente fatto nel mio caso) è possibile disattivare le transazioni su tutti i metodi pubblici con l'aggiunta di

static transactional = false 

per la classe di servizio.

+6

Sì, è molto comune per servizi di utilità che non scrivono nel database. È una buona ottimizzazione delle prestazioni poiché altrimenti si incorre in un piccolo costo di creazione di una transazione non necessaria per ogni chiamata. –