Как предотвратить исключение исключений из откат транзакции под Grails?

У службы My Grails возникает проблема, когда проглоченное исключение, не связанное с транзакцией, вызывает откат транзакции, даже если она не связана с устойчивостью объекта домена.

В моем сервисе у меня есть что-то вроде

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

То, что я вижу, это то, что когда у меня есть исключение, когда я очищаю старый файл, я регистрирую его и проглатываю, но он все равно вызывает откат транзакции, хотя я уже сделал обновление объекта домена.

Как ограничить транзакцию области до завершения очистки или есть другой способ получить исключение очистки, чтобы не вызвать откат?

Только для записи я использую Grails 2.1.1

Ответ 1

Вы можете использовать аннотации, чтобы выполнить более мелкомасштабную демаркацию транзакций. По умолчанию услуги являются транзакционными, а все общедоступные методы являются транзакционными. Но если вы используете аннотации @Transactional, Grails не делает все транзакционным - у вас есть полный контроль.

Исключения времени выполнения автоматически вызывают откат, но проверенных исключений нет. Несмотря на то, что Groovy не требует, чтобы вы улавливали отмеченные исключения, эта функция является Spring, которая не знает об обработке исключений Groovy.

Транзакции реализуются путем упаковки вашего экземпляра класса службы в прокси. Если исключение "ускользает" от прокси-сервера, будет ли оно пойманным или нет, откат будет уже выполнен.

Итак, у вас есть несколько вариантов. Аннотировать updateSomething как @Transactional, но не аннотировать cleanUpOldFile:

import org.springframework.transaction.annotation.Transactional

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

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

Вы также можете аннотировать cleanUpOldFile одним или несколькими непроверенными исключениями, которые не должны откатывать транзакцию (или в других случаях, проверенных исключениях, которые должны), например

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

Ответ 2

В дополнение к @Burt Beckwith ответьте, если у вас есть служба, где вы просто не хотите транзакций (что я на самом деле делал в моем случае), вы можете повернуть выключения транзакций по всем общедоступным методам, добавив

static transactional = false

в класс службы.