Spojrzenie na źródło PołączeniePool.java
wydaje się, że trafiłeś w ten fragment kodu w borrowConnection()
metoda:
//we didn't get a connection, lets see if we timed out
if (con == null) {
if ((System.currentTimeMillis() - now) >= maxWait) {
throw new SQLException("[" + Thread.currentThread().getName()+"] " +
"Timeout: Pool empty. Unable to fetch a connection in " + (maxWait / 1000) +
" seconds, none available["+busy.size()+" in use].");
} else {
//no timeout, lets try again
continue;
}
}
Więc zgodnie z tym twoje połączenie jest Zerowe .
Wartość con
jest pobierany w linii:
PooledConnection con = idle.poll();
jeśli śledzisz kod, zobaczysz idle
to (w zależności od konfiguracji, ale domyślnie) FairBlockingQueue
. Możesz sprawdzić implementację, aby uzyskać wskazówki.
Ogólnie rzecz biorąc, zawsze musisz zamykać zestawy wyników, instrukcje i połączenia, a używane połączenia powinny zostać poprawnie zwolnione z powrotem do puli. Niewykonanie tego poprawnie może spowodować, że połączenia nigdy nie zostaną zamknięte => nigdy nie będą ponownie dostępne do ponownego użycia (pula połączeń "przecieka" ).
Sugeruję skonstruowanie szczegółowego rejestrowania stanu puli i monitorowanie go w celu wyizolowania problemu.
Niektóre wytyczne Apache dotyczące zapobiegania wyciekom puli połączeń z bazą danych:
removeAbandoned="true"
porzucone połączenia z bazą danych są usuwane i poddawane recyklingowi
removeAbandonedTimeout="60"
ustaw liczbę sekund, przez które połączenie z bazą danych było bezczynne, zanim zostanie uznane za porzucone
logAbandoned="true"
zarejestrować ślad stosu kodu, który porzucił zasoby połączenia z bazą danych. Pamiętaj, że „rejestrowanie porzuconych połączeń zwiększa obciążenie dla każdego pożyczonego połączenia, ponieważ musi zostać wygenerowany ślad stosu”.
Nadal myślę, że nieznacznie zwiększę maxWait
wartość (1200, 1500, 1700 - po prostu eksperymentuj, nie będzie różnicy w czasie reakcji z perspektywy użytkownika) wyeliminuje te rzadkie przypadki, w których nadal masz problemy.