2016-05-16 91 views
0

如果我在我的Grails命令對象中使用GORM域對象,命令對象會自動提交對域對象的更改,即使我沒有調用save()方法。默認情況下,Grails命令對象爲什麼會提交對域對象的更改?

我想綁定到命令對象中的GORM對象,但不保存或提交對數據庫的更改。如果我的控制器或我的服務引發異常,我希望事務回滾。

我可以用下面的註釋強制我想要的行爲,但那感覺就像我在做這個艱難的方式。

Controller Class = @Transactional(readOnly = true) 
Controller action method = @Transactional 
Command Object Class = @Transactional(readOnly = true) 
Service Class = @Transactional 

我做錯了什麼,Grails域對象是否應該由命令對象自動提交,除非我添加所有這些註釋?

回答

1

這不是特定於命令對象,它是控制器操作的一般特徵。默認情況下,開放會話視圖模式處於活動狀態,其中創建Hibernate會話並在動作運行前將其綁定到線程本地,並在動作完成後刷新並關閉。從數據庫中檢索到的任何持久實例(顯式地由於查詢或在數據綁定期間隱式地)將保持連接到打開的會話,並且在會話刷新時被骯髒檢查。任何修改後的實例都會將其更改與其他排隊操作一起刷新,無論是否帶有save()調用。

使整個方法(或類)事務和只讀可能是矯枉過正。更直接的方法是將實例檢索爲只讀,例如,使用read()而不是get(),在執行條件查詢等時調用readOnly方法,或者通過調用各自的discard()方法來「分離」修改的實例。另一個選項是在動作結束時清除會話,因此沒有任何東西可以自動刷新,例如,

AnyDomainClass.withSession { it.clear() } 

注意,在「只讀」模式中獲取的實例可以有自己堅持的變化,但Hibernate不會自動做這些情況下任何東西,只有當你明確地調用save()發生。

+0

但我所看到的是綁定在命令對象中的對象隱式地在命令對象之後和控制器動作的第一行之前提交,而不是在動作結束之後提交。除非我如上所述註釋,否則我似乎在命令對象中獲得一個事務,並在該操作中獲得另一個事務。 – DAC

+0

你可以創建一個小型測試應用程序來演示這個嗎?我想看看,所以如果你可以在Github或其他在線repo上做些工作,甚至可以將代碼壓縮並通過電子郵件發送給我,我希望能夠追蹤到這一點。如果這是一個真正的bug,那麼報告它會很好。 –

+0

行,找到了!演示應用程序沒有相同的行爲。事實證明,我們通過在命令對象中注入一個UtilService來幫助驗證,從而導致了這個問題。該服務是**沒有註釋@Transactional(readOnly = true)',所以使用它開始了一個事務並返回到提交該事務的控制器操作。註釋UtilService'@Transactional(readOnly = true)'解決了這個問題。 – DAC

相關問題