2014-04-08 19 views
7

Wystąpił problem z moim obiektem HibernateInterceptor. Rozszerzam EmptyInterceptor i zastępuję metodę onFlushDirty. Używam tej metody do ręcznego sprawdzania brudnych wartości (porównaj poprzednie wartości z bieżącymi wartościami), aby zapisać dzienniki audytu dla zmienionych encji. Problem polega na tym, że w pewnych określonych sytuacjach zdarza się, że ta sama jednostka jest przekazywana do metody onFlushDirty kilka razy przed wywołaniem metody postFlush. Poprzednie wartości i bieżące wartości nie zmieniają się z połączenia na połączenie. Więc mój dziennik kontroli zapisuje kilka razy te same zmiany. Jeśli właściwość mojej jednostki zmienia się (np. Z NEW na IN_PROGRESS), zmiana ta jest przekazywana dwa lub więcej razy do onFlushDirty. Dlaczego tak się dzieje? To jest naprawdę dziwne zachowanie i nie oczekuje się w mojej opinii.Element przechwytujący hibernację onFlushDirty wywoływany wiele razy z tymi samymi wartościami

Wywołanie przechwytywacza onFlushDirty jest spowodowane zachowaniem stanu hibernacji w postaci auto-flush. Kiedy kwerenda jest wykonywana podczas sesji, opróżnia wszystkie brudne jednostki w sesji. Spodziewam się, że zostanie to zrobione tylko raz dla brudnej istoty, ale wydaje się, że byt jest nadal oznaczony jako "brudny", nawet po kolorze. Następnie kolejne zapytanie jest wykonywane w ramach sesji i ponownie - obiekt jest ponownie opróżniany. Stare wartości i bieżące wartości są takie same jak przy pierwszym spłukiwaniu.

Próbowałem odtworzyć ten problem w teście, ale nie mogłem sprowokować takich wielokrotnych powtórzeń. Mam nadzieję, że eksperci Hibernate mogą mi pomóc, zanim będę musiał debugować cały kod Hibernate.

Pozdrawiam, Chris

Odpowiedz

7

Po pewnym debugowania, znalazłem przyczynę wielu wezwań onFlushDirty:

Jak wyjaśniono powyżej, flushmode w mojej aplikacji jest ustawiony na AUTO. Zanim kwerenda zostanie wykonana w ramach transakcji, Hibernate decyduje, czy należy czyścić brudne elementy, czy nie. Niezależnie od wyniku tej decyzji: metoda onFlushDirty w HibernateInterceptor jest wywoływana z całą pewnością dla każdego brudnego obiektu w sesji, nawet jeśli zdecydowano, że nie zostanie ona później przepłukana.

Jeśli jednostka typu A znajduje się w stanie brudnym w sesji, a zapytanie dla obiektu typu B jest wykonywane w ramach tej sesji, Hibernate nie opróżnia tego obiektu, ponieważ nie ma wpływu na tabelę, której używa zapytanie, a więc kolor nie jest potrzebny.

Jeśli w trakcie sesji wykonywanych jest wiele zapytań, może się zdarzyć, że metoda onFlushDirty zostanie wywołana kilka razy w tym samym zabrudzonym obiekcie, ale nigdy tak naprawdę nie zostanie przepłukana do bazy danych i będzie zanieczyszczona do czasu zatwierdzenia transakcji.

Wystarczy popatrzeć na klasy hibernacji DefaultAutoFlushEventListener

public void onAutoFlush(AutoFlushEvent event) throws HibernateException { 
... 
    if (flushIsReallyNeeded(event, source)) { 
      log.trace("Need to execute flush"); 
... 
    } 
    else { 
     log.trace("Dont need to execute flush"); 
... 
    } 
} 
+0

Cześć Chris, ale w jaki sposób pan rozwiązać swój problem? –

+0

Cześć Chris, ale w jaki sposób rozwiązałeś swój problem z powielaniem zapisów w dzienniku kontroli? –

+1

Cześć Ołeksandr, śledzę przechodzące już jednostki na mapie zapisywania wątków, aby upewnić się, że jednostka nie jest zapisana dwukrotnie. Kiedy Hibernate wywołuje metodę "afterTransactionCompletion" przechwytywacza, kontynuuję i wykonuję przetwarzanie dziennika audytu dla zebranych encji. Mam nadzieję, że pomaga ... – theFriedC

Powiązane problemy