Ponieważ zakleszczenia zdarzają się tak często, wygląda na to, że niektóre wątki aplikacji utrzymują blokady przez dłuższy czas.
Każdy wątek w aplikacji będzie korzystał z własnego połączenia/połączeń z bazą danych podczas uzyskiwania dostępu do bazy danych, więc z punktu widzenia bazy danych dwa wątki to dwa różne klienty, które konkurują o blokady bazy danych.
Jeśli wątek utrzymuje blokady przez dłuższy czas i nabywa je w określonej kolejności, a drugi wątek nadchodzi, uzyskując te same blokady, ale w innej kolejności, nastąpi zakleszczenie (patrz tutaj aby uzyskać szczegółowe informacje na temat tej częstej przyczyny zakleszczenia).
W operacjach odczytu występują również zakleszczenia, co oznacza, że niektóre wątki również uzyskują blokady odczytu. Dzieje się tak, jeśli wątki wykonują transakcje w REPEATABLE_READ
poziom izolacji lub SERIALIZABLE
.
Aby rozwiązać ten problem, spróbuj wyszukać zastosowania Isolation.REPEATABLE_READ
i Isolation.SERIALIZABLE
w projekcie, aby sprawdzić, czy jest on używany.
Alternatywnie użyj domyślnego READ_COMMITTED
poziom izolacji i adnotuj encje za pomocą @Version
, do obsługi współbieżności przy użyciu optymistycznego blokowania
zamiast tego.
Spróbuj także zidentyfikować długotrwałe transakcje, co zdarza się czasami, gdy @Transactional
jest umieszczony w niewłaściwym miejscu i zawija na przykład przetwarzanie całego pliku w przykładzie przetwarzania wsadowego, zamiast wykonywać transakcje linia po linii.
Jest to konfiguracja log4j do rejestrowania tworzenia/usuwania menedżerów encji i rozpoczynania/zatwierdzania/wycofywania transakcji:
<!-- spring entity manager and transactions -->
<logger name="org.springframework.orm.jpa" additivity ="false">
<level value="debug" />
<appender-ref ref="ConsoleAppender" />
</logger >
<logger name="org.springframework.transaction" additivity ="false">
<level value="debug" />
<appender-ref ref="ConsoleAppender" />
</logger >
- Czy mogę w jakiś sposób wykonać zapytanie aktualizacyjne (zarówno JPA, jak i natywne) bez konieczności blokowania tabeli przez @Transactional?
Zapytania aktualizacyjne są możliwe za pośrednictwem zapytań natywnych lub JPQL .
- Czy mogę w jakiś sposób wejść do sesji bez użycia @Transactional? Na przykład zaplanowany wątek próbuje odczytać pole Lazy na Entity zwraca LazyInitializationException — brak sesji, jeśli metoda nie jest oznaczona adnotacją @Transactional
W metodach bez @Transactional
, zapytania będą wykonywane we własnym menedżerze encji i zwracają tylko odłączone encje, ponieważ sesja jest zamykana natychmiast po uruchomieniu zapytania.
więc leniwe wyjątki inicjalizacji w metodach bez @Transactional
jest normalne. Możesz ustawić je na @Transactional(readOnly=true)
również.