Proponuje zagadkę.
W bazie jest 2 użytkowników z tego samego miasta: Andrzej i Wojtek. Metoda getAllUsersFromCity() tworzy odpowiedni obiekt Criteria i zwraca listę użytkowników z danego miasta. Przyjmijmy, że kod funkcji testCache() wykonywany jest w ramach jednej sesji hibernata:
public void testCache(){ printUsers(); //w tym momecie ktoś inny edytuje jednego z użytkowników, //w zupełnie innej sesji lub bezpośrednio na bazie, //zmienia nazwe z Andrzej na Bartek printUsers(); } public void printUsers(){ List<User> users = dao.getAllUsersFromCity("city"); foreach(User user : users){ System.out.println(user.getName()); } }
Co zostanie wyświetlone na ekranie?
a)AndrzejWojtekAndrzejWojtek
b)AndrzejWojtekBartekWojtek
To normalne, że jak pobierzesz rekord za pomocą get/load to następne wywołanie zwraca rekord z cache bez znaczenia czy zmienił się on w bazie czy nie....
OdpowiedzUsuńJeżeli chodzi o cache'owanie zapytań to wyobraź sobie, że to działa "idealnie" czyli po zmianie Andrzej na Bartek metoda getAllUsersFromCity zwraca AndrzejWojtekBartekWojtek co też jest do dupy bo może się okazać ze w tej samej sesji cześć algorytmu podejmie decyzje na podstawie AndrzejWojtekAndrzejWojtek a druga cześć na podstawie AndrzejWojtekBartekWojtek
Podsumowując wołaj metode getAllUsersFromCity raz i zadbaj o concurrency
Mirku, czy sprawdzałeś to doświadczalnie? Bo ja wczoraj poświęciłem na to sporo czasu i do wczoraj wydawało mi się, że drugie wywołanie metody powinno zwrócić, tak jak napisałeś, już świeże dane (czyli BartekWojtek) - ale tak nie jest... W obrębie tej samej sesji dostaje za każdym razem, AndrzejWojtek i AndrzejWojtek.
OdpowiedzUsuńJest jeszcze jeden aspekt, który może mięć na to wpływ (choć szczerze wątpię). Testy przeprowadzałem na aplikacji, która wykorzystuje Envers'a. I szperając po necie natknąłem się na taki wpis:
http://www.java-forums.org/database/45267-jtable-refresh-problem-hibernate-session.html
- drugi komentarz.
Jakoś nie chce mi się wierzyć, żeby Envers miał tu aż taki wpływ, ale tego przyznam szczerze nie zbadałem.
Zależy jakie masz zapytanie ja nigdy nie wyciągam zapytaniem obiektów tylko projekcje...jeśli wyciągniesz obiekty to "sprytny" hibernate stwierdzi ze wynikiem zapytania są obiekty o id 1,2,3 które ma już w L1 więc zamiast danych które zwróciło zapytanie da Ci obiekty z cache...dla mnie dziwne jest ze pomimo pola VERSION i jego zmiany hibernate nadal ma to gdzieś ...
OdpowiedzUsuńZ wielką siłą (hibernate) wiąże się wielka odpowiedzialność :)
Dla @Version nie sprawdzałem, ale skoro mówisz, że i tak nic to nie zmienia... Mimo wszystko takie podejście ma jakiś sens. Załóżmy, że user Andrzej jest już w sesji. Z poziomu bazy zmieniamy na Bartek. Robimy select wszystkich userów. I gdyby ten select miał zwrócić świeże dane, to nagle w tej samej sesji Andrzej stałby się Bartkiem, co chyba byłoby bardziej problematyczne...
OdpowiedzUsuńTrzeba po prostu być świadomym jak działa L1.
Projekcje są rozwiązaniem, ale nie uniwersalnym. Poza tym wygodniej pobiera się listę danych obiektów.