如何防止异常导致Grails下的事务回滚?

如何防止异常导致Grails下的事务回滚?,grails,transactions,gorm,Grails,Transactions,Gorm,我的Grails服务遇到了一个问题,与事务无关的异常导致事务回滚,即使它与域对象的持久性无关 在我的服务中,我有一些类似于 updateSomething(domainObj) { def oldFilename = domainObj.filename def newFilename = getNewFilename() domainObj.filename = newFilename domainObj.save(flush: true) try

我的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
    }
}
我看到的是,当我在清理旧文件时出现异常时,我会记录它并吞下它,但它仍然会导致事务回滚,即使我已经更新了域对象

如何将作用域事务限制为在清理之前完成,或者是否有其他方法获取清理异常以不导致回滚


仅就我使用Grails2.1.1的记录而言,您可以使用注释来进行更细粒度的事务划分。默认情况下,服务是事务性的,所有公共方法都是事务性的。但是,如果您使用任何
@Transactional
注释,Grails不会使所有内容都是事务性的——您可以完全控制

运行时异常会自动触发回滚,但选中的异常不会。尽管Groovy不要求捕获检查过的异常,但该特性是Spring的一部分,它不知道Groovy异常处理

事务是通过将服务类实例包装到代理中来实现的。如果一个异常“逃逸”了代理,不管它是否被捕获,回滚将已经发生

所以你有几个选择。将
updateMething
注释为
@Transactional
,但不要注释
cleanUpOldFile

import org.springframework.transaction.annotation.Transactional

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

def cleanUpOldFile(...) {
   ...
}
您还可以使用一个或多个不应回滚事务的未检查异常(或在其他用例中应回滚事务的已检查异常)对cleanUpOldFile进行注释,例如

除了您的答案之外,如果您有一个不需要事务的服务(在我的案例中,我确实这样做了),您可以通过添加

static transactional = false

服务类。

有一件事我不完全理解,我的catch块不应该捕获所有异常,包括运行时异常和已检查异常吗?Spring怎么知道我有异常呢?我假设它注意到了服务层之间的异常,在我的例子中,一个服务层与另一个服务层对话。这是唯一对我有意义的事情。如果您所做的只是将@Transactional(noRollbackFor=[FooException,BarException])添加到cleanUpOldFile(),那么这对类中的所有其他方法有什么影响?它们是否仍然是事务性的?如果我指定
norolllbackfor=[Exception]
,这是否仍然会为未捕获的异常回滚?自Grails v3.2.0以来,选中的异常也会触发回滚。是的,这对于不写入数据库的实用程序服务来说非常常见。这是一个很好的性能优化,因为否则,为每个调用创建不必要的事务会产生很小的成本。此问题可能会导致“org.hibernate.LazyInitializationException:无法初始化代理-无会话”。我以为我的异常被正确捕获了,但没有意识到我的try/catch的位置已经太晚了!
static transactional = false