Nigdy nie pisz swojego rozwiązania do buforowania
Innym sposobem na przyspieszenie pracy z bazą danych jest buforowanie obiektów, o które prosiliśmy już wcześniej.
Ważny! Nigdy nie pisz własnego rozwiązania do buforowania. To zadanie ma tak wiele pułapek, o których nawet nie śniłeś.
Problem 1 — opróżnianie pamięci podręcznej . Czasami występują zdarzenia, gdy obiekt musi zostać usunięty z pamięci podręcznej lub zaktualizowany w pamięci podręcznej. Jedynym sposobem, aby zrobić to kompetentnie, jest przekazanie wszystkich żądań do bazy danych przez silnik pamięci podręcznej. W przeciwnym razie za każdym razem będziesz musiał jawnie powiedzieć pamięci podręcznej, które znajdujące się w niej obiekty mają zostać usunięte lub zaktualizowane.
Problem 2 - brak pamięci . Buforowanie wydaje się świetnym pomysłem, dopóki nie odkryjesz, że obiekty w pamięci zajmują dużo miejsca. Do efektywnego działania pamięci podręcznej aplikacji serwera potrzebne są dodatkowe dziesiątki gigabajtów pamięci.
A ponieważ zawsze brakuje pamięci, potrzebna jest skuteczna strategia usuwania obiektów z pamięci podręcznej. Jest to trochę podobne do modułu wyrzucania elementów bezużytecznych w Javie. A jak pamiętacie, przez dziesięciolecia najtęższe umysły wymyślały różne sposoby znakowania przedmiotów z pokolenia na pokolenie itp.
Problem 3 – różne strategie . Jak pokazuje praktyka, różne strategie przechowywania i aktualizowania w pamięci podręcznej są skuteczne dla różnych obiektów. Wydajny system buforowania nie może stosować tylko jednej strategii dla wszystkich obiektów.
Problem 4 - Efektywne przechowywanie plików . Nie możesz po prostu przechowywać obiektów w pamięci podręcznej. Obiekty zbyt często zawierają odniesienia do innych obiektów itd. W tym tempie nie będziesz potrzebować modułu wyrzucania elementów bezużytecznych: po prostu nie będzie miał czego usuwać.
Dlatego zamiast przechowywania samych obiektów, czasami znacznie wydajniejsze jest przechowywanie wartości ich prymitywnych pól. I systemy do szybkiego konstruowania obiektów na ich podstawie.
W rezultacie otrzymasz w pamięci cały wirtualny DBMS, który powinien działać szybko i zużywać mało pamięci.
Buforowanie bazy danych
Oprócz buforowania bezpośrednio w programie Java, buforowanie jest często organizowane bezpośrednio w bazie danych.
Istnieją cztery duże podejścia:
Pierwszym podejściem jest denormalizacja bazy danych . Serwer SQL przechowuje dane w pamięci inaczej niż w tabelach.
Kiedy dane są przechowywane na dysku w tabelach, bardzo często programiści starają się w jak największym stopniu unikać powielania danych - proces ten nazywa się normalizacją bazy danych. Tak więc, aby przyspieszyć pracę z danymi w pamięci, wykonywany jest proces odwrotny - denormalizacja bazy danych. Kilka powiązanych tabel można już przechowywać w połączonej formie - w postaci ogromnych tabel itp.
Drugie podejście to buforowanie zapytań . I wyniki zapytania.
DBMS widzi, że bardzo często przychodzą do niego takie same lub podobne żądania. Następnie po prostu zaczyna buforować te żądania i ich odpowiedzi. Ale jednocześnie musisz upewnić się, że wiersze, które uległy zmianie w bazie danych, są usuwane z pamięci podręcznej w odpowiednim czasie.
Takie podejście może być bardzo skuteczne w przypadku człowieka, który może analizować zapytania i pomóc DBMS dowiedzieć się, jak najlepiej je buforować.
Trzecie podejście to baza danych w pamięci .
Inne powszechnie stosowane podejście. Pomiędzy serwerem a DBMS umieszczona jest kolejna baza danych, która przechowuje wszystkie swoje dane tylko w pamięci. Jest również nazywany In-Memory-DB. Jeśli masz wiele różnych serwerów uzyskujących dostęp do tej samej bazy danych, za pomocą In-Memory-DB możesz zorganizować buforowanie na podstawie typu konkretnego serwera.
Przykład:
Podejście 4 — klaster bazy danych . Kilka baz tylko do odczytu.
Innym rozwiązaniem jest użycie klastra: kilka DBMS tego samego typu zawiera identyczne dane. Jednocześnie możesz odczytywać dane ze wszystkich baz danych, a zapisywać tylko do jednej. Który jest następnie synchronizowany z resztą baz danych.
To bardzo dobre rozwiązanie, ponieważ jest łatwe w konfiguracji i sprawdza się w praktyce. Zwykle na jedno żądanie do bazy danych o zmianę danych przychodzi do niej 10-100 żądań odczytu danych.
Rodzaje buforowania w Hibernate
Hibernate obsługuje trzy poziomy buforowania:
- Buforowanie na poziomie sesji (Session)
- Buforowanie na poziomie SessionFactory
- Żądania buforowania (i ich wyniki)
Możesz spróbować przedstawić ten system w postaci takiej figury:
Najprostszy rodzaj buforowania (zwany także buforowaniem pierwszego poziomu ) jest realizowany na poziomie sesji Hibernate. Hibernacja zawsze domyślnie korzysta z tej pamięci podręcznej i nie można jej wyłączyć .
Rozważmy od razu następujący przykład:
Employee director1 = session.get(Employee.class, 4);
Employee director2 = session.get(Employee.class, 4);
assertTrue(director1 == director2);
Mogłoby się wydawać, że zostaną tutaj wykonane dwa zapytania do bazy danych, ale tak nie jest. Po pierwszym zapytaniu do bazy obiekt Pracownik zostanie zbuforowany. A jeśli ponownie wyślesz zapytanie do obiektu w tej samej sesji, Hibernate zwróci ten sam obiekt Java.
Ten sam obiekt oznacza, że nawet odwołania do obiektów będą identyczne. To naprawdę ten sam obiekt.
Metody save() , update() , saveOrUpdate() , load() , get() , list() , iterate() i scroll() będą zawsze używać pamięci podręcznej pierwszego poziomu. Właściwie nie ma nic więcej do dodania.
Buforowanie drugiego poziomu
Jeśli pamięć podręczna pierwszego poziomu jest powiązana z obiektem sesji, pamięć podręczna drugiego poziomu jest powiązana z obiektem sesji.Fabryka sesji. Co oznacza, że widoczność obiektów w tej pamięci podręcznej jest znacznie szersza niż w pamięci podręcznej pierwszego poziomu.
Przykład:
Session session = factory.openSession();
Employee director1 = session.get(Employee.class, 4);
session.close();
Session session = factory.openSession();
Employee director2 = session.get(Employee.class, 4);
session.close();
assertTrue(director1 != director2);
assertTrue(director1.equals(director2));
W tym przykładzie do bazy danych zostaną wykonane dwa zapytania. Hibernate zwróci identyczne obiekty, ale nie będzie to ten sam obiekt - będą miały różne referencje.
Buforowanie drugiego poziomu jest domyślnie wyłączone . Mamy więc dwa zapytania do bazy danych zamiast jednego.
Aby go włączyć, musisz napisać następujące wiersze w pliku hibernate.cfg.xml:
<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletEhCacheProvider"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
Po włączeniu buforowania drugiego poziomu zachowanie Hibernacji nieco się zmieni:
Session session = factory.openSession();
Employee director1 = session.get(Employee.class, 4);
session.close();
Session session = factory.openSession();
Employee director2 = session.get(Employee.class, 4);
session.close();
assertTrue(director1 == director2);
Dopiero po tych wszystkich manipulacjach zostanie włączona pamięć podręczna drugiego poziomu, aw powyższym przykładzie zostanie wykonane tylko jedno zapytanie do bazy danych.
GO TO FULL VERSION