Nie pamiętam, czy Hibernate faktycznie przechowuje instancje PreparedStatement, czy też polega na dostawcy połączenia, aby je ponownie wykorzystać. (Szybkie skanowanie BatcherImpl sugeruje ponowne użycie ostatniego PreparedStatement w przypadku wielokrotnego wykonywania tego samego SQL)
Myślę, że dokumentacja c3p0 stara się pokazać, że dla wielu sterowników JDBC, PreparedStatement nie jest przydatne:niektóre sterowniki skończą po prostu splatają parametry po stronie klienta, a następnie i tak przekażą zbudowaną instrukcję SQL do bazy danych . Dla tych sterowników PreparedStatements nie stanowią żadnej korzyści, a wszelkie wysiłki związane z ich ponownym wykorzystaniem są marnotrawstwem. (Często zadawane pytania dotyczące Postgresql JDBC mówią, że tak było w przypadku Postgresql przed wersją 3 protokołu serwera, a w dokumentacji znajdują się bardziej szczegółowe informacje).
W przypadku sterowników, które skutecznie obsługują PreparedStatements, prawdopodobnie konieczne jest ponowne użycie wystąpień PreparedStatement, aby uzyskać jakiekolwiek korzyści. Na przykład, jeśli kierowca realizuje:
- Connection.prepareStatement(sql) - utwórz oświadczenie po stronie serwera
- PreparedStatement.execute(..) etc - wykonaj tę instrukcję po stronie serwera
- PreparedStatement.close() - cofnij alokację instrukcji po stronie serwera
Biorąc to pod uwagę, jeśli aplikacja zawsze otwiera przygotowaną instrukcję, wykonuje ją raz, a następnie zamyka ponownie, to nadal żadnych korzyści; w rzeczywistości może być gorzej, ponieważ potencjalnie jest teraz więcej podróży w obie strony. Aplikacja musi więc trzymać się instancji PreparedStatement. Oczywiście prowadzi to do innego problemu:jeśli aplikacja zawiesza się na zbyt wielu, a każda instrukcja po stronie serwera zużywa trochę zasobów, może to prowadzić do problemów po stronie serwera. W przypadku, gdy ktoś korzysta bezpośrednio z JDBC, może to być zarządzane ręcznie - wiadomo, że niektóre instrukcje są wielokrotnego użytku i dlatego są przygotowywane; niektóre nie są i po prostu używają instancji przejściowych instrukcji. (Jest to pominięcie innej korzyści płynących z przygotowanych instrukcji:obsługi unikania argumentów)
Dlatego właśnie c3p0 i inne pule połączeń również mają przygotowane pamięci podręczne instrukcji - pozwala to kodowi aplikacji uniknąć zajmowania się tym wszystkim. Instrukcje są zwykle przechowywane w pewnej ograniczonej puli LRU, więc typowe instrukcje ponownie wykorzystują instancję PreparedStatement.
Ostatnie elementy układanki polegają na tym, że kierowcy JDBC mogą sami zdecydować się na spryt i zrobić to; a serwery mogą same zdecydować się na spryt i wykryć klienta składającego oświadczenie, które jest strukturalnie podobne do poprzedniego.
Biorąc pod uwagę, że Hibernate sam nie przechowuje pamięci podręcznej instancji PreparedStatement, musisz zlecić to c3p0, aby uzyskać z nich korzyści. (Które należy zmniejszyć obciążenie dla typowych wyciągów ze względu na ponowne wykorzystanie planów w pamięci podręcznej). Jeśli c3p0 nie buforuje przygotowanych instrukcji, sterownik zobaczy, że aplikacja przygotowuje instrukcję, wykonuje ją, a następnie ponownie ją zamyka. Wygląda na to, że sterownik JDBC ma ustawienie „próg”, aby uniknąć obciążenia serwera przygotowania/wykonywania w przypadku, gdy aplikacja zawsze to robi. Więc tak, musisz mieć c3p0 do buforowania instrukcji.
Mam nadzieję, że to pomoże, przepraszam, że jest trochę za długi. Odpowiedź brzmi tak .