2013-04-04 6 views
12

Mein Grails-Dienst hat ein Problem, bei dem eine verschluckte Ausnahme, die nicht mit einer Transaktion zusammenhängt, das Rollback der Transaktion verursacht, auch wenn sie nicht mit der Persistenz des Domänenobjekts zusammenhängt.Wie verhindere ich, dass Ausnahmen unter Grails einen Transaktions-Rollback verursachen?

In meinem Dienst Ich habe etwas entlang der Linien von

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

Was ich sehe, ist, dass, wenn ich Ausnahme, wenn ich die alte Datei am Aufräumen, ich es einzuloggen und schlucken, aber es immer noch bewirkt, dass die Transaktion zurückgesetzt wird, obwohl das Domänenobjekt bereits aktualisiert wurde.

Wie kann ich begrenzen, dass die Scope-Transaktion vor der Bereinigung abgeschlossen wird, oder gibt es eine andere Möglichkeit, die Cleanup-Ausnahme zu erhalten, die kein Rollback verursacht?

Gerade für die Aufzeichnung verwende ich Grails 2.1.1

Antwort

26

Sie Anmerkungen können feinkörnige Transaktionsdemarkation zu tun. Standardmäßig sind Dienste transaktional und alle öffentlichen Methoden sind transaktional. Aber wenn Sie irgendwelche @Transactional Annotationen verwenden, macht Grails nicht alles transaktional - Sie haben die vollständige Kontrolle.

Laufzeitausnahmen lösen automatisch Rollbacks aus, aber geprüfte Ausnahmen nicht. Auch wenn Groovy nicht erfordert, dass Sie überprüfte Ausnahmen abfangen, ist das Feature eine Spring-Sache, die nichts über die Groovy-Exception-Behandlung weiß.

Transaktionen werden implementiert, indem Ihre Serviceklasseninstanz in einen Proxy eingebunden wird. Wenn eine Exception den Proxy "verlässt", egal ob er dann gefangen wird oder nicht, ist der Rollback bereits passiert.

Sie haben also ein paar Optionen. Anmerken updateSomething als @Transactional aber nicht mit Anmerkungen versehen cleanUpOldFile:

import org.springframework.transaction.annotation.Transactional 

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

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

Sie können auch mit Anmerkungen versehen cleanUpOldFile mit einem oder mehreren nicht markiert Ausnahmen, die nicht rollen sollte wieder eine Transaktion (oder in anderen Anwendungsfällen überprüft Ausnahmen sollten), z.B.

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

Eine Sache, die ich nicht vollständig verstehe, sollte mein catch-Block nicht alle Ausnahmen erfassen, sowohl Laufzeit als auch überprüft? Woher weiß Spring überhaupt, dass ich Ausnahmen habe? –

+0

Ich nehme an, dass es die Ausnahme zwischen den Service-Ebenen bemerkt, in meinem Fall hatte ich eine Service-Schicht, die mit einer anderen sprach. Das ist das einzige, was für mich einen Sinn ergibt. –

+0

Wenn Sie nur @Transactional (noRollbackFor = [FooException, BarException]) zu cleanUpOldFile() hinzufügen, welchen Effekt hat das für jede andere Methode in der Klasse? Sind sie noch transaktional oder nicht? –

8

Neben @Burt Beckwith ‚s Antwort, wenn Sie einen Service, wo Sie wollen einfach nicht, Transaktionen (die ich in meinem Fall tatsächlich tat) Sie Transaktionen auf allen öffentlichen Methoden ausschalten kann durch Zugabe von

static transactional = false 

an die Service-Klasse.

+6

Ja, das ist sehr üblich für Dienstprogramme, die nicht in die Datenbank schreiben. Dies ist eine gute Leistungsoptimierung, da Sie sonst für jede Verbindung nur geringe Kosten für die Erstellung einer unnötigen Transaktion aufwenden müssen. –