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
}
}
我所看到的是,当我清理旧文件时遇到异常时,我会记录并吞下它,但它仍会导致事务回滚,即使我已经完成了域对象的更新。 / p>
如何在清理之前限制范围事务完成,或者是否有其他方法可以使清理异常不导致回滚?
仅供我使用Grails 2.1.1
的记录答案 0 :(得分:28)
您可以使用注释来进行更细粒度的事务划分。默认情况下,服务是事务性的,所有公共方法都是事务性的。但是,如果您使用任何@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(...) {
...
}
答案 1 :(得分:8)
除了@Burt Beckwith的回答之外,如果您有一个您不想要交易的服务(我实际上是在我的情况下做过),您可以通过添加所有公共方法来关闭交易
static transactional = false
到服务类。