Polecam dodanie @Startup
@Singleton
klasa, która nawiązuje połączenie JDBC z bazą danych PostgreSQL i używa LISTEN
i NOTIFY
do obsługi unieważniania pamięci podręcznej.
Aktualizacja :Oto kolejne interesujące podejście, wykorzystujące pgq i zbiór pracowników do unieważniania.
Sygnalizacja unieważnienia
Dodaj wyzwalacz do aktualizowanej tabeli, który wysyła komunikat NOTIFY
za każdym razem, gdy jednostka jest aktualizowana. W PostgreSQL 9.0 i nowszych to NOTIFY
może zawierać ładunek, zwykle identyfikator wiersza, więc nie musisz unieważniać całej pamięci podręcznej, tylko zmienioną encję. W starszych wersjach, w których ładunek nie jest obsługiwany, można dodać unieważnione wpisy do tabeli dziennika ze znacznikiem czasu, do której odpytuje klasa pomocnicza, gdy otrzyma komunikat NOTIFY
lub po prostu unieważnij całą pamięć podręczną.
Twoja klasa pomocnicza teraz LISTEN
s na NOTIFY
zdarzenia wysyłane przez wyzwalacz. Gdy otrzyma NOTIFY
zdarzenia, może unieważnić pojedyncze wpisy w pamięci podręcznej (patrz poniżej) lub opróżnić całą pamięć podręczną. Możesz nasłuchiwać powiadomień z bazy danych dzięki obsłudze nasłuchu/powiadomienia PgJDBC. Będziesz musiał rozpakować wszystkie zarządzane przez pulę połączeń java.sql.Connection
aby uzyskać dostęp do podstawowej implementacji PostgreSQL, aby można było przesłać ją do org.postgresql.PGConnection
i wywołaj getNotifications()
na nim.
Alternatywa dla LISTEN
i NOTIFY
, można odpytywać tabelę dziennika zmian na czasomierzu, a wyzwalacz w tabeli problemów dołącza zmienione identyfikatory wierszy i znaczniki czasu zmian do tabeli dziennika zmian. To podejście będzie przenośne, z wyjątkiem potrzeby innego wyzwalacza dla każdego typu bazy danych, ale jest nieefektywne i mniej terminowe. Będzie to wymagało częstego, nieefektywnego odpytywania i nadal będzie miało opóźnienie, którego nie ma podejście słuchania/powiadamiania. W PostgreSQL możesz użyć UNLOGGED
tabeli, aby nieco obniżyć koszty tego podejścia.
Poziomy pamięci podręcznej
EclipseLink/JPA ma kilka poziomów buforowania.
Pamięć podręczna pierwszego poziomu znajduje się w EntityManager
poziom. Jeśli encja jest dołączona do EntityManager
przez persist(...)
, merge(...)
, find(...)
itd., a następnie EntityManager
jest zobowiązany do zwrócenia tego samego wystąpienia tego podmiotu gdy jest ponownie dostępny w tej samej sesji, niezależnie od tego, czy aplikacja nadal ma do niej odniesienia. Ta podłączona instancja nie będzie aktualna, jeśli zawartość Twojej bazy danych uległa zmianie.
Pamięć podręczna drugiego poziomu, która jest opcjonalna, znajduje się w EntityManagerFactory
poziomie i jest bardziej tradycyjną pamięcią podręczną. Nie jest jasne, czy masz włączoną pamięć podręczną drugiego poziomu. Sprawdź swoje dzienniki EclipseLink i plik persistence.xml
. Możesz uzyskać dostęp do pamięci podręcznej drugiego poziomu za pomocą EntityManagerFactory.getCache()
; zobacz Cache
.
@thedayofcondor pokazał, jak opróżnić pamięć podręczną drugiego poziomu za pomocą:
em.getEntityManagerFactory().getCache().evictAll();
ale możesz także eksmitować poszczególne obiekty za pomocą evict(java.lang.Class cls, java.lang.Object primaryKey)
zadzwoń:
em.getEntityManagerFactory().getCache().evict(theClass, thePrimaryKey);
którego możesz użyć ze swojego @Startup
@Singleton
NOTIFY
listener, aby unieważnić tylko te wpisy, które uległy zmianie.
Pamięć podręczna pierwszego poziomu nie jest taka prosta, ponieważ jest częścią logiki aplikacji. Będziesz chciał dowiedzieć się, jak EntityManager
, dołączone i odłączone jednostki itp. Jedną z opcji jest zawsze używanie odłączonych encji dla danej tabeli, gdzie używasz nowego EntityManager
za każdym razem, gdy pobierasz jednostkę. To pytanie:
Unieważnianie sesji JPA EntityManager
zawiera przydatne omówienie obsługi unieważniania pamięci podręcznej menedżera encji. Jednak jest mało prawdopodobne, aby EntityManager
cache to Twój problem, ponieważ usługa sieciowa RESTful jest zwykle implementowana przy użyciu krótkiego EntityManager
sesje. Jest to prawdopodobnie problem tylko wtedy, gdy używasz rozszerzonych kontekstów trwałości lub jeśli tworzysz i zarządzasz własnym EntityManager
sesji zamiast używania trwałości zarządzanej przez kontener.