2013-04-04 27 views
12

我的Grails服务存在一个问题,即与事务无关的吞噬异常导致事务回滚,即使它与域对象的持久性无关。如何防止异常导致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

回答

26

您可以使用注释做更精细的事务划分的记录。默认情况下,服务是事务性的,所有公共方法都是事务性的。但是,如果您使用任何@Transactional注释,Grails不会使所有事务都成为事实 - 您可以完全控制。

运行时异常会自动触发回滚,但检查异常不会。尽管Groovy并不要求你捕获检查异常,但这个特性是一个不了解Groovy异常处理的Spring事物。

事务通过将您的服务类实例包装在代理中实现。如果一个异常“逃脱”代理,无论是否被捕获,回滚将会发生。

所以你有几个选择。注释updateSomething@Transactional但不标注cleanUpOldFile

import org.springframework.transaction.annotation.Transactional 

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

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

您也可以标注cleanUpOldFile与一个或多个未检查异常,不应该回滚事务(或其他使用情况检查的异常应),例如

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

有一件事我不完全明白,不应该我的catch块捕获所有异常,运行时和检查? Spring如何知道我有什么异常? – 2013-04-05 00:51:56

+0

我认为它是注意到服务层之间的异常,在我的情况下,我有一个服务层与另一个服务层交谈。这是唯一对我有意义的事情。 – 2013-04-05 01:04:55

+0

如果您只需将@Transactional(noRollbackFor = [FooException,BarException])添加到cleanUpOldFile(),那么对类中的每个其他方法会有什么影响?他们仍然是交易型的吗? – 2014-08-25 15:51:28

8

除了@Burt Beckwith的答案,如果你有一个服务,你只是不想交易(我其实在我的情况一样),你可以通过添加

关闭所有的公共方法交易
static transactional = false 

到服务类。

+6

是的,对于不写入数据库的实用程序服务而言,这非常常见。这是一个很好的性能优化,因为否则您会为每次调用创建一个不必要的事务的成本很小。 – 2013-04-05 01:35:19