2014-06-19 40 views
6

我的Grails項目從升級到1.3.7和2.4.0修復與新的Grails版本的各種問題後,後洗淨模式中,我意識到,沒有做過任何對象的變化將是除了調用save(flush:true)外,其他所有(除此之外)都一直存在。Grails的改變從自動到手動

對於Grails 1.3.7,使用save()保存域實例時的默認行爲是,由於休眠flushMode =>FlushMode.AUTO,更改會自動保留。在Grails 2.4.0中,這不再是事實。任何控制器操作或服務類中的hibernate會話的默認flushMode爲FlushMode.MANUAL。自舉,它有一個FlushMode.AUTO值和一個控制器動作,其中它具有價值FlushMode.MANUAL檢索sessionFactory.currentSession.flushMode

事情變得陌生了。這可以通過創建一個新的Grails應用程序,並把println "flushMode = $sessionFactory.currentSession.flushMode"自舉和一個控制器動作進行驗證(例如指數())。

我已經通過各類論壇搜索的最後2天,並沒有發現任何合理的解釋,爲什麼這個曾在Grails的2.4.0改變(或者甚至在較早版本)。我只找到評論說,它的種類有風險有FlushMode.MANUAL,因爲你可以查詢數據庫時,一些人已被修改後碰到過時對象。

我知道:

  • grails.gorm.autoFlush = true在配置你可以強制刷新:真正到每一個省()
  • 在Hibernate3和hibernate4默認flushMode是FlushMode.AUTO
  • 其無法設置flushMode在Config.groovy和DataSource.groovy中。我嘗試了所有這一切,並沒有做任何工作: hibernate.flush.mode = 'auto' hibernate.flushMode = 'auto' hibernate.session.flush.mode = 'auto' hibernate.session.flushMode = 'auto' dataSource.hibernate.flush.mode = 'auto' dataSource.hibernate.flushMode = 'auto' dataSource.hibernate.session.flush.mode = 'auto' dataSource.hibernate.session.flushMode = 'auto' dataSource.flush.mode = 'auto' dataSource.flushMode = 'auto' dataSource.session.flush.mode = 'auto' dataSource.session.flushMode = 'auto'

請有人可以扔在這個小光?

其實我想知道的話,Grails的2.4.0 FlushMode.MANUAL現在所需的默認?

如果是這樣:

  • 什麼是評論「...的建議是不是我們完全禁用自動清空模式......」由彼得·萊德布魯克在GRAILS-7180
  • 什麼是最佳實踐不會遇到過時對象的問題,特別是在對域對象執行復雜操作時,修改,創建新實例和查詢都是混合的。

非常感謝 - 安迪


在閱讀Graemes回答,他的意見,我想更好地澄清什麼,我掙扎,並添加了證明行爲以下簡化域和控制器類:

域類信息:

class Msg { 

    String text 

    static constraints = { 
     text nullable:true 
    } 
} 

和味精控制器:

class MsgController { 
    def sessionFactory 

    def index = { 
     def out = ["*** flushMode when in controller/index = \ 
        $sessionFactory.currentSession.flushMode"] 
     Msg.list().each { out << "$it.id: text=$it.text" } 
     render out.join('<br>') 
    } 

    // this save does persist the new msg object, 
    // even if flushMode = MANUAL 
    def save1 = { 
     def out = ["*** flushMode when in controller/save = \ 
        $sessionFactory.currentSession.flushMode"] 
     def msg = new Msg(text:'hallo') 
     if (!msg.save()) { 
      out << "msg has errors! " + msg.errors 
     } 
     out << "msg $msg.id created with text = $msg.text" 
     render out.join('<br>') 
    } 

    // this save does NOT persist the new msg object, even if its valid 
    // (difference is calling hasErrors() 
    def save2 = { 
     def out = ["*** flushMode when in controller/save = \ 
        $sessionFactory.currentSession.flushMode"] 
     def msg = new Msg(text:'hallo') 
     if (msg.hasErrors() && !msg.save()) { 
      out << "msg has errors! " + msg.errors 
     } 
     out << "msg $msg.id created with text = $msg.text" 
     render out.join('<br>') 
    } 
} 


所以調用http://localhost/appname/msg/save1輸出爲:

*** flushMode when in controller/save1 = MANUAL 
msg 1 created with text = hallo 

在這裏,我不明白,爲什麼Hibernate持久化對象,即使你flushMode是MANUAL。

,並呼籲http://localhost/appname/msg/save2當輸出爲:

*** flushMode when in controller/save2 = MANUAL 
msg null created with text = hallo 

對象沒有得到持續,因爲Hibernate沒有發出沖水,從而從未調用SQL「更新...」命令。

但現在看來,不僅flushMode是一個問題,而且如果有人調用hasErrors()或不!我更加困惑......

如果你在Grails 1.3.7中做這個例子,保存動作(save1和save2)會保持新創建的msg對象!

回答

8

Grails在驗證之前會將刷新模式設置爲手動,以防止在驗證過程中刷新任何更改(這可能很常見,因爲您可能有自定義驗證程序查詢現有數據)。

https://github.com/grails/grails-data-mapping/blob/master/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateDomainClassValidator.java#L60

如果有任何驗證錯誤也不會設置刷新模式重新設置爲AUTO。這是爲了防止無效對象被持久化。

你看到的是你可能有驗證錯誤發生,雖然你可以強制刷新,但不建議。

+0

感謝您的解釋。那是有道理的。但是爲什麼Grails在控制器動作中切換到MANUAL,即使沒有域對象被保存(完全使用)?我用一個控制器編寫了一個小小的Grails應用程序,沒有任何領域類來驗證。在控制器索引操作中,我只放置了1 LOC'println「flushMode = $ sessionFactory.currentSession.flushMode」 –

+0

對於讀取操作,Grails使用只讀事務。只讀事務使用手動刷新模式。讀操作使用只讀事務的原因是因爲它提高了性能,因爲Hibernate不需要對只讀對象進行髒檢查。這可能是你所看到的。 –

+0

查看原始問題的更新域和控制器示例 –