2010-06-05 50 views
12

當服務中引發RuntimeException時,我一直在使用Grail的回滾功能將所有服務更新爲事務性。我已經在大多數情況下,這樣做:在Grails服務中回滾事務

def domain = new Domain(field: field) 
if (!domain.save()) { 
    throw new RuntimeException() 
} 

不管怎麼說,我想驗證這確實會回滾事務......這讓我開始思考是否在這一點上它已經被提交。還如果沒有,會設置flush:真的改變了嗎?我不是很熟悉Spring/Hibernate如何做到這一點:)

回答

15

是的,它會做到這一點。

默認情況下,Grails中的事務是在服務方法級別處理的。如果方法正常返回,則事務將被提交,如果拋出RuntimeException,事務將被回滾。

注意這意味着即使您在服務器方法中保存對象時使用flush:true on,如果拋出RuntimeException,數據庫更改仍會回滾。

例如:

class MyService { 

def fiddle(id,id2){ 
    def domain = Domain.findById(id) 

    domain.stuff = "A change" 
    domain.save(flush:true) // will cause hibernate to perform the update statements 

    def otherDomain = OtherDomain.findById(id2)  

    otherDomain.name = "Fiddled" 

    if(!otherDomain.save(flush:true)){ // will also write to the db 
    // the transaction will be roled back 
    throw new RuntimeException("Panic what the hell happened") 
    }               
} 
} 

什麼我不是100%的透明與Grails的是,如果一個檢查的異常是在直java的拋出會發生什麼/彈簧世界上默認行爲是事務攔截器提交交易,通過這可以在配置中重寫。

注意:有一個警告,那就是您的數據庫必須支持您正在更新的表上的事務。是的,這是戳在MySQL :)

這也適用於Domain.withTransaction方法。

+0

太棒了,謝謝! – RyanLynch 2010-06-05 14:31:03

+0

很高興能成爲服務 – 2010-06-05 14:33:44

+0

擴展RuntimeException的自定義異常應該沒問題吧? 此外,您可以通過設置: dialect = org.hibernate.dialect啓用MySQL中的事務。MySQLInnoDBDialect in dataSource :) – RyanLynch 2010-06-05 15:09:10

2

只是想添加額外的評論接受的答案,這是太長,以適應評論。

什麼我不與Grails的100%清楚的是,如果一個檢查異常被拋出

默認情況下,該異常不能檢查,或者該交易將不會被捲起會發生什麼背部。顯然這是一個春天的事情。

如果您確實想檢查某個方法的例外情況,則可以明確將服務方法標記爲@Transactional並使用rollbackFor參數列出哪些異常仍應導致回滾。 (請注意,我並沒有真正測試過這個)。

請注意,雖然標記服務中的任何一種方法與@Transactional禁用其他方法與事務的自動包裝。所以,如果你只爲一個人做,你必須爲所有人做。確保你真的需要宣佈那些檢查的例外;)

你可以閱讀更多關於此http://docs.grails.org/latest/guide/services.html