Как лучше всего управлять подключением к базе данных в сервлете Java?
В настоящее время я просто открываю соединение в функции init(), а затем закрываю его в destroy().
Однако меня беспокоит, что «постоянное» удержание соединения с базой данных может быть плохим.
Это правильный способ справиться с этим? Если нет, то какие варианты лучше?
edit: чтобы дать немного больше пояснений: я пытался просто открывать / закрывать новое соединение для каждого запроса, но при тестировании я увидел проблемы с производительностью из-за создания слишком большого количества подключений.
Есть ли смысл в совместном использовании соединения по нескольким запросам? Запросы для этого приложения почти все предназначены только для чтения и поступают довольно быстро (хотя запрашиваемые данные довольно малы).
Я изменю принятый ответ, так как правила сообщества :) Однако я бы хотел, чтобы было больше объяснений. Когда я задал этот вопрос несколько месяцев назад, я был новичком во всей сцене "java webapp", и его ответ на самом деле не объяснял, о чем он говорит.
Проблема в том, что это вики сообщества, поэтому баллы не начисляются. Я тоже напишу небольшой ответ ниже.




Вы должны держать соединение с базой данных открытым только до тех пор, пока оно вам нужно, что в зависимости от того, что вы делаете, вероятно, находится в пределах возможностей ваших методов doGet/doPost.
Более того, не гарантируется, что destroy () будет вызываться
Приложение, над которым я работаю, имеет очень частые запросы от многих клиентов, не будет ли такой риск использовать все соединения с базой данных? (или просто создать слишком много, чтобы быть быстрым?) Просто прошу разъяснений, а не пытаюсь опровергнуть свой ответ.
Конечно, вы должны использовать пул соединений, если хотите, чтобы ваше приложение масштабировалось. Таким образом, у вас будет контроль над макс. количество подключений.
Вам определенно следует использовать пул соединений.
Вы объединяете свои связи? В противном случае вам, вероятно, следует уменьшить накладные расходы на открытие и закрытие ваших соединений.
Как только это не мешает, просто держите соединение открытым столько, сколько необходимо, как предложил Джон.
Лучший способ, и я сейчас ищу в Google лучший справочный лист, - это использовать пулы.
При инициализации вы создаете пул, который содержит X объектов подключения SQL к вашей базе данных. Храните эти объекты в каком-нибудь списке, например в ArrayList. Каждый из этих объектов имеет частное логическое значение isLeased, длительное время последнего использования и Connection. Когда вам нужно соединение, вы запрашиваете его из пула. Пул либо предоставит вам первое доступное соединение, проверяя переменную isLeased, либо создаст новое и добавит его в пул. Обязательно установите отметку времени. Как только вы закончите с подключением, просто верните его в пул, который установит для isLeased значение false.
Чтобы избежать постоянного подключения к базе данных, вы можете создать рабочий поток, который иногда будет проходить через пул и видеть, когда в последний раз использовалось подключение. Если прошло достаточно времени, он может закрыть это соединение и удалить его из пула.
Преимущества использования этого заключаются в том, что вам не нужно долго ждать, пока объект Connection подключится к базе данных. Ваши уже установленные соединения можно использовать повторно, сколько захотите. И вы сможете установить количество подключений в зависимости от того, насколько, по вашему мнению, будет загружено ваше приложение.
Обычно вы обнаружите, что открытием соединений по запросу легче управлять. Это означает, что в методе doPost () или doGet () вашего сервлета.
Открытие его в init () делает его доступным для всех запросов, а что происходит, когда у вас есть параллельные запросы?
Я бы использовал Commons DBCP. Это проект Apache, который управляет пулом соединений за вас.
Вы просто получите свое соединение в своем doGet или doPost, запустите свой запрос, а затем закроете соединение в блоке finally. (con.close () просто возвращает его в пул, но не закрывает его).
DBCP может управлять тайм-аутом подключения и восстанавливать после него. Как вы сейчас делаете, если ваша база данных выйдет из строя на какой-то период времени, вам придется перезапустить приложение.
Пул соединений, связанный с источником данных, должен помочь. Вы можете получить соединение из источника данных в методе запроса сервлета (doget / dopost и т. д.).
dbcp, c3p0 и многие другие пулы соединений могут делать то, что вы ищете. Пока вы объединяете соединения, вы можете захотеть объединить утверждения и PreparedStatements; Кроме того, если ваша среда READ HEAVY, как вы указали, вы можете захотеть кэшировать некоторые результаты, используя что-то вроде ehcache.
BR,
~ А
Я действительно не согласен с использованием Commons DBCP. Вам действительно следует полагаться на контейнер, чтобы управлять пулом соединений за вас.
Поскольку вы используете сервлеты Java, это подразумевает работу в контейнере сервлетов, и все основные контейнеры сервлетов, с которыми я знаком, обеспечивают управление пулом соединений (спецификация Java EE может даже потребовать этого). Если ваш контейнер использует DBCP (как это делает Tomcat), отлично, в противном случае просто используйте то, что предоставляет ваш контейнер.
Абсолютно! Ради всего святого, делегируйте это контейнеру и просто реализуйте поиск JNDI для ресурса. Нет НИКАКОЙ причины заниматься этим самостоятельно.
Думаю, это зависит от того, как развернуто ваше приложение. Мы выполняем развертывание на многих различных серверах приложений, и работать с DBCP проще, чем изучать другой способ настройки пулов соединений для каждого сервера приложений. В любом случае все в порядке. У меня также были некоторые серверы приложений, которые не работают с дисками jdbc (Websphere)
Я согласен с ScArcher2. Я предпочитаю, чтобы приложение было автономным и не полагалось на внешнюю конфигурацию для запуска. В идеале нужно уметь развернуть войну и готово!
Объедините это.
Кроме того, если вы используете необработанный JDBC, вы можете изучить что-то, что поможет вам управлять Connection, PreparedStatement и т. д. Если у вас нет очень жестких требований «легковесности», использование поддержки Spring JDBC, например, упростит ваш код. lot- и вы не обязаны использовать какую-либо другую часть Spring.
См. Несколько примеров здесь:
http://static.springframework.org/spring/docs/2.5.x/reference/jdbc.html
Как все говорят, вам нужно использовать пул соединений. Почему? Что случилось? И т.п.
Что не так с вашим решением
Я знаю это, потому что когда-то думал, что это была хорошая идея. Проблема двоякая:
Почему пул подключений
Пулы подключений дают вам массу преимуществ, но, прежде всего, они решают проблемы
Когда подключиться
Где-то в стеке вызовов, инициированном в вашем сервисном делегате (doPost, doGet, doDisco, что угодно), вы должны получить соединение, а затем вы должны сделать правильные вещи и вернуть его в блоке finally. Я должен упомянуть, что чувак, главный архитектор C#, однажды однажды сказал, что вам следует использовать блоки finally в 100 раз больше, чем блоки catch. Более правдивых слов никогда не было ...
Какой пул подключений
Вы находитесь в сервлете, поэтому вам следует использовать пул соединений, который предоставляет контейнер. Ваш код JNDI будет полностью нормальным, за исключением того, как вы получаете соединение. Насколько мне известно, все контейнеры сервлетов имеют пулы соединений.
В некоторых комментариях к ответам выше предлагается использовать вместо этого конкретный API пула соединений. Ваша WAR должна быть переносимой и «просто развертываемой». Я считаю, что это в корне неверно. Если вы используете пул соединений, предоставляемый вашим контейнером, ваше приложение будет развертываться в контейнерах, охватывающих несколько машин, и все те причудливые вещи, которые предоставляет спецификация Java EE. Да, нужно будет написать дескрипторы развертывания, специфичные для контейнера, но это метод EE, мон.
Один комментатор упоминает, что определенные пулы соединений, предоставляемые контейнером, не работают с драйверами JDBC (он / она упоминает Websphere). Это звучит совершенно неправдоподобно и нелепо, так что, вероятно, это правда. Когда случаются подобные вещи, выбросьте все, что вы «должны делать», в мусор и делайте все, что можете. Иногда нам за это платят :)
Вы действительно должны отметить вопрос Джека Леоу как правильный. Материал J2EE (или как там его называют в 2009 году) использует сервер приложений по какой-то причине ... В любом случае, круто то, что если вы сделаете то, что говорите выше, с помощью init и destroy, я думаю, что сервлет будет последовательно складываться. запросы БД, поэтому несколько потоков будут работать медленно.