2014-06-19 14 views
6

Po aktualizacji mojego projektu Grails z 1.3.7 na 2.4.0 i po naprawieniu różnych problemów związanych z nową wersją Grails, zdałem sobie sprawę, że żadna ze zmian dokonanych w żadnym obiekcie nie będzie utrzymywał się już (w ogóle), chyba że wywołano save(flush:true).Tryb płukania zmieniony w grails z AUTO na MANUAL

Z Grails 1.3.7 domyślnym zachowaniem przy zapisywaniu instancji domeny przy użyciu save() jest to, że zmiany są utrzymywane automatycznie, ze względu na hibernację flushMode =>FlushMode.AUTO. W Grails 2.4.0 to już nie jest prawdą. Domyślna wartość parametru flushMode sesji hibernacji w dowolnym działaniu kontrolera lub klasie usługi to FlushMode.MANUAL.

Rzeczy stają się jeszcze dziwniejsze podczas pobierania sessionFactory.currentSession.flushMode w BootStrap, gdzie ma on wartość FlushMode.AUTO, a także w akcji kontrolera, która ma wartość FlushMode.MANUAL. Można to sprawdzić, tworząc nową aplikację grails i umieszczając println "flushMode = $sessionFactory.currentSession.flushMode" w BootStrap i akcji kontrolera (np. Index()).

Przez ostatnie 2 dni przeszukiwałem wszelkiego rodzaju fora i nie znalazłem żadnego rozsądnego wyjaśnienia, dlaczego to musiało zostać zmienione w Grails 2.4.0 (a może nawet we wcześniejszych wersjach). Znalazłem tylko komentarze, które mówią o ryzyku posiadania FlushMode.MANUAL, ponieważ możesz uruchomić się na nieaktualnych obiektach podczas wysyłania zapytań do db po zmodyfikowaniu innych.

wiem, że:

  • z grails.gorm.autoFlush = true w config można wymusić kolor: true, aby każdy save()
  • w hibernate3 i hibernate4 domyślnej flushMode jest FlushMode.AUTO
  • jej nie można ustawić flushMode w Config.groovy ani w DataSource.groovy. Wypróbowałem to wszystko i nic nie pomogło: 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'

Czy ktoś może rzucić w to trochę światła?

Właściwie chciałbym wiedzieć, czy w Grails 2.4.0 FlushMode.MANUAL jest teraz pożądanym domyślnym?

A jeśli tak, to:

  • Co jest z komentarzem „... Propozycja nie jest to, że możemy całkowicie wyłączyć tryb płukania AUTO ...” Petera Ledbrook w GRAILS-7180
  • Jaki jest najlepszych praktyk aby nie napotkać problemów z nieaktualnymi obiektami, szczególnie podczas wykonywania złożonych manipulacji na obiektach domen, w których modyfikowanie, tworzenie nowych instancji i wykonywanie zapytań jest mieszane.

Dzięki bardzo - Andi


Po przeczytaniu Graemes odpowiedź i swoje uwagi, starałem się lepiej wyjaśnić, co walczę z i dodaje następujące uproszczone domeny i kontrolerów klas, które pokazują, że zachowanie :

klasa Domain błędzie:

class Msg { 

    String text 

    static constraints = { 
     text nullable:true 
    } 
} 

i kontroler msg:

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>') 
    } 
} 


Więc wywołanie http://localhost/appname/msg/save1 wyjście jest:

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

Tutaj ja nie rozumiem, dlaczego hibernacji utrzymuje obiekt, nawet ty flushMode ma wartość MANUAL.

A kiedy dzwoni http://localhost/appname/msg/save2 wyjście jest:

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

Obiekt nie dostać się dlatego hibernacji nie wydaje się równo, a więc nigdy nie nazywa sql „update ...” polecenia.

Ale teraz wydaje się, że nie tylko tryb flushMode jest problemem, ale także jeśli wywołuje on funkcję hasErrors() lub nie! Jestem zaintrygowany jeszcze bardziej ...

Jeśli zrobisz ten przykład w Grails 1.3.7, obie akcje zapisu (save1 i save2) utrzymają nowo utworzony obiekt msg!

Odpowiedz

8

Grails ustawią tryb płukania na Ręczny przed sprawdzaniem poprawności, aby zapobiec przepłukiwaniu zmian podczas sprawdzania poprawności (może to być dość powszechne, ponieważ możesz mieć niestandardowy weryfikator, który zapytuje istniejące dane).

Zobacz 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

Jeśli są jakieś błędy sprawdzania nie będzie ustawiony tryb płukania z powrotem na AUTO. Ma to zapobiec utrwalaniu nieprawidłowych obiektów.

To, co widzisz, to prawdopodobnie błędy walidacji i chociaż możesz wymusić kolor, nie jest to wskazane.

+0

Dzięki za wyjaśnienie. To ma sens. Ale dlaczego Grails przełącza się na RĘCZNE w działaniu kontrolera, nawet jeśli żadne obiekty domeny nie są zapisywane (używane w ogóle)? Napisałem niewielką aplikację Grails z tylko jednym kontrolerem i bez klasy domeny, aby to zweryfikować. W akcji indeksu kontrolera umieszczam tylko 1 LOC 'println" flushMode = $ sessionFactory.currentSession.flushMode "' –

+0

Dla operacji odczytu Grails używa transakcji tylko do odczytu. Transakcja typu "tylko do odczytu" używa trybu ręcznego RĘCZNIE. Operacje odczytu powodują użycie transakcji tylko do odczytu, ponieważ poprawia wydajność, ponieważ Hibernate nie ma potrzeby czyszczenia obiektów tylko do odczytu. To może być to, co widzisz. –

+0

Zobacz oryginalne pytanie ze zaktualizowanym przykładem domeny i kontrolera. –