Najlepszy sposób zarządzania połączeniem z bazą danych dla serwletów Java

Jaki jest najlepszy sposób zarządzania połączeniem z bazą danych w Serwletie Java?

Obecnie po prostu otwieram połączenie w funkcji init(), a następnie zamykam je w destroy().

Obawiam się jednak, że "stałe" trzymanie połączenia z bazą danych może być złą rzeczą.

Czy to jest właściwy sposób, aby sobie z tym poradzić? Jeśli nie, Jakie są lepsze opcje?

Edit: aby dać trochę więcej wyjaśnienia: próbowałem po prostu otworzyć / zamknąć nowe połączenie dla każdego prośba, ale z testowaniem widziałem problemy z wydajnością z powodu tworzenia zbyt wielu połączeń.

Czy jest jakaś wartość w dzieleniu połączenia przez wiele żądań? Żądania dla tej aplikacji są prawie wszystkie "Tylko do odczytu" i przychodzą dość szybko (chociaż żądane dane są dość małe).

Author: TM., 2008-10-28

9 answers

Nie zgadzam się z używaniem Commons DBCP. Naprawdę powinieneś skorzystać z kontenera, aby zarządzać poolingiem połączeń.

Ponieważ używasz serwletów Java, oznacza to uruchomienie w kontenerze serwletów, a wszystkie główne kontenery serwletów, które znam, zapewniają zarządzanie pulą połączeń (Specyfikacja Java EE może nawet tego wymagać). Jeśli twój kontener używa DBCP (tak jak robi to Tomcat), świetnie, w przeciwnym razie po prostu użyj tego, co zapewnia twój kontener.

 14
Author: Jack Leow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-27 22:57:02

Jak wszyscy mówią, musisz użyć puli połączeń. Dlaczego? Co tam? Itd.

Co jest nie tak z Twoim rozwiązaniem

Wiem o tym, ponieważ również myślałem, że to był dobry pomysł, Dawno, dawno temu. Problem jest dwojaki:

  1. wszystkie wątki (żądania servletów są obsługiwane z jednym wątkiem na każdy) będą współdzielić to samo połączenie. Wnioski będą zatem przetwarzane pojedynczo. Jest to bardzo powolne, nawet jeśli po prostu siedzisz w jednej przeglądarce i opierasz się na F5 klucz. Spróbuj: te rzeczy brzmią na wysokim poziomie i abstrakcyjnie, ale są empiryczne i testowalne.
  2. Jeśli połączenie zostanie przerwane z jakiegokolwiek powodu, metoda init nie zostanie ponownie wywołana (ponieważ servlet nie zostanie wyłączony z usługi). Nie staraj się poradzić sobie z tym problemem, umieszczając try-catch w dogecie lub dopostie, ponieważ wtedy będziesz w piekle(coś w rodzaju pisania serwera aplikacji bez pytania).
  3. wbrew temu, co można by pomyśleć, nie będziesz miał problemów z transakcjami, ponieważ początek transakcji jest powiązany z wątkiem, a nie tylko z połączeniem. Może się mylę, ale skoro i tak jest to złe rozwiązanie, nie przejmuj się.

Dlaczego Pula Połączeń

Pule połączeń dają Ci wiele zalet, ale przede wszystkim rozwiązują problemy
    [11]}nawiązanie prawdziwego połączenia z bazą danych jest kosztowne. Pula połączeń zawsze ma kilka dodatkowych połączeń wokół i daje jeden z nich.
  1. Jeśli połączenie nie działa, Pula połączeń wie, jak otworzyć nowe]}
  2. bardzo ważne: każdy wątek ma swoje własne połączenie. Oznacza to, że threading jest obsługiwany tam, gdzie powinien być: na poziomie DB. DBs są bardzo wydajne i mogą z łatwością obsługiwać jednoczesne żądania.
  3. inne rzeczy (jak centralizacja lokalizacji JDBC connect strings, itp.), ale są miliony artykułów, książek itp. on this

Kiedy uzyskać połączenie

Gdzieś w call stack zainicjowany w Twoim delegacie serwisu (doPost, doGet, doDisco, cokolwiek) powinieneś uzyskać połączenie, a następnie powinieneś postąpić słusznie i zwrócić je w końcu blok. Powinienem wspomnieć, że główny architekt C# powiedział raz na jakiś czas, że należy używać finally bloków 100x więcej niż catch bloków. Prawdziwsze słowa Nigdy nie wypowiedziane...

Która Pula Połączeń

Jesteś w serwlecie, więc powinieneś użyć puli połączeń, którą zapewnia kontener. Twój kod JNDI będzie być całkowicie normalne, z wyjątkiem sposobu uzyskania połączenia. Z tego co wiem, wszystkie kontenery servletów mają pulę połączeń.

Niektóre komentarze dotyczące powyższych odpowiedzi sugerują użycie określonego interfejsu API puli połączeń. Twoja wojna powinna być przenośna i " po prostu rozlokować."Myślę, że to jest w zasadzie złe. Jeśli korzystasz z puli połączeń dostarczonej przez kontener, Twoja aplikacja będzie można wdrożyć na kontenerach obejmujących wiele maszyn i wszystkie te fantazyjne rzeczy, które są specyfikacją Java EE zapewnia. Tak, deskryptory wdrożenia specyficzne dla kontenerów będą musiały zostać zapisane, ale tak właśnie jest, mon.

Jeden z komentatorów wspomina, że niektóre pule połączeń dostarczane przez kontenery nie działają ze sterownikami JDBC (wspomina o Websphere). To brzmi całkowicie naciągane i niedorzeczne, więc prawdopodobnie to prawda. Kiedy takie rzeczy się zdarzają, wyrzuć wszystko, co "powinieneś zrobić" do śmieci i rób, co możesz. Za to czasem nam płacą:)

 22
Author: Yar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-25 22:52:55

Użyłbym Commons DBCP . Jest to projekt Apache, który zarządza pulą połączeń dla Ciebie.

Po prostu dostajesz połączenie w doGet lub doPost Uruchom zapytanie, a następnie zamknij połączenie w końcu bloku. (con.close () po prostu zwraca go do puli, w rzeczywistości go nie zamyka).

DBCP może zarządzać timeoutami połączeń i odzyskiwać je. Sposób, w jaki obecnie robisz rzeczy, jeśli baza danych ulegnie awarii na dowolny okres czasu, będziesz musiał ponownie uruchomić swój podanie.

 4
Author: ScArcher2,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-27 21:40:31

Łączysz swoje znajomości? Jeśli nie, prawdopodobnie powinieneś zmniejszyć koszty otwarcia i zamknięcia połączeń.

Gdy to się skończy, utrzymuj połączenie otwarte tak długo, jak będzie trzeba, jak zasugerował John.

 2
Author: Jack Leow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-27 21:35:02

Najlepszym sposobem, a obecnie Szukam przez Google lepszego arkusza referencyjnego, jest użycie basenów.

Podczas inicjalizacji tworzysz pulę zawierającą x liczbę obiektów połączenia SQL z Twoją bazą danych. Przechowuje te obiekty w jakiejś liście, takiej jak ArrayList. Każdy z tych obiektów ma prywatny boolean dla 'isLeased', długi na czas, kiedy był ostatnio używany i połączenie. Gdy potrzebujesz połączenia, prosisz o jedno z basenu. Basen albo da ci Pierwsze dostępne połączenie, sprawdzając zmienną isLeased, lub utworzy nowe i doda je do puli. Upewnij się, że ustawiłeś znacznik czasu. Po zakończeniu połączenia, po prostu zwróć je do puli, która ustawi isLeased na false.

Aby uniknąć ciągłego łączenia bazy danych, możesz utworzyć wątek roboczy, który od czasu do czasu będzie przechodził przez pulę i sprawdzał, kiedy ostatnio użyto połączenia. Jeśli minęło wystarczająco dużo czasu, może się zamknąć to połączenie i usuń je z basenu.

Korzyści płynące z tego użycia polega na tym, że nie ma długiego czasu oczekiwania na połączenie obiektu Connection z bazą danych. Twoje już ustanowione połączenia mogą być ponownie wykorzystane, tak jak chcesz. Będziesz mógł ustawić liczbę połączeń w oparciu o to, jak myślisz, że Twoja aplikacja będzie zajęta.

 2
Author: Joel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-27 21:35:23

Połączenie z bazą danych powinno być otwarte tylko tak długo, jak tego potrzebujesz, co zależy od tego, co robisz, prawdopodobnie mieści się w zakresie Twoich metod doGet/doPost.

 1
Author: John Topley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-27 21:31:30

Pool it.

Ponadto, jeśli robisz raw JDBC, możesz zajrzeć do czegoś, co pomoże Ci zarządzać połączeniem, przygotować oświadczenie itp. Jeśli nie masz bardzo ścisłych wymagań "lekkości", używanie na przykład obsługi JDBC Springa znacznie uprości Twój kod - i nie jesteś zmuszony do korzystania z żadnej innej części Springa.

Zobacz kilka przykładów tutaj:

Http://static.springframework.org/spring/docs/2.5.x/reference/jdbc.html

 1
Author: alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-27 23:35:04

Pula połączeń powiązana ze źródłem danych powinna załatwić sprawę. Połączenie można uzyskać z dataSource w metodzie Servlet request(doget/dopost, itp.).

Dbcp, c3p0 i wiele innych pul połączeń może zrobić to, czego szukasz. Podczas łączenia połączeń możesz chcieć łączyć instrukcje i PreparedStatements; Ponadto, jeśli używasz ciężkiego środowiska odczytu, jak wskazałeś, możesz chcieć buforować niektóre wyniki za pomocą czegoś takiego jak ehcache.

BR,
~A

 1
Author: anjanb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-28 17:10:02

Zwykle okazuje się, że otwieranie połączeń na żądanie jest łatwiejsze do zarządzania. Oznacza to w metodzie doPost () lub doGet () twojego servletu.

Otwarcie go w init () sprawia, że jest on dostępny dla wszystkich żądań i co się dzieje, gdy masz jednocześnie żądań?

 0
Author: Vincent Ramdhanie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-27 21:35:49