Лучший способ управлять подключением к базе данных для сервлета Java

StackOverflow https://stackoverflow.com/questions/241454

Вопрос

Как лучше всего управлять подключением к базе данных в сервлете Java?

В настоящее время я просто открываю соединение в init() функцию, а затем закройте ее в destroy().

Однако я обеспокоен тем, что «постоянное» сохранение соединения с базой данных может быть плохим.

Это правильный способ справиться с этим?Если нет, то какие варианты лучше?

редактировать:чтобы дать немного больше разъяснений:Я пробовал просто открывать/закрывать новое соединение для каждого запроса, но при тестировании я обнаружил проблемы с производительностью из-за создания слишком большого количества соединений.

Есть ли какой-либо смысл в совместном использовании соединения по нескольким запросам?Запросы к этому приложению почти все «только для чтения» и поступают довольно быстро (хотя запрашиваемые данные довольно малы).

Это было полезно?

Решение

Я на самом деле не согласен с использованием Commons DBCP. Вы действительно должны обратиться к контейнеру, чтобы управлять пулом соединений для вас.

Поскольку вы используете сервлеты Java, это подразумевает работу в контейнере сервлетов и всех основных контейнерах сервлетов, с которыми я знаком, обеспечивают управление пулом соединений (спецификация Java EE может даже потребовать этого). Если ваш контейнер использует DBCP (как это делает Tomcat), то отлично, просто используйте то, что обеспечивает ваш контейнер.

Другие советы

Как все говорят, вам нужно использовать пул соединений. Зачем? Как дела? Etc.

Что не так с вашим решением

Я знаю это, так как я тоже думал, что когда-то это была хорошая идея. Проблема двоякая:

<Ол>
  • Все потоки (запросы сервлета обслуживаются по одному потоку на каждый) будут использовать одно и то же соединение. Поэтому запросы будут обрабатываться по одному. Это очень медленно, даже если вы просто сидите в одном браузере и опираетесь на клавишу F5. Попробуйте: это звучит высокоуровнево и абстрактно, но эмпирически и проверяемо.
  • Если по какой-либо причине соединение разрывается, метод init больше не будет вызываться (поскольку сервлет не будет выведен из эксплуатации). Не пытайтесь решить эту проблему, поместив try-catch в doGet или doPost, потому что тогда вы окажетесь в аду (что-то вроде написания сервера приложений без запроса).
  • Вопреки тому, что можно подумать, у вас не будет проблем с транзакциями, поскольку начало транзакции связано с потоком, а не только с соединением. Я могу ошибаться, но так как это в любом случае плохое решение, не парься.
  • Почему пул соединений

    Пулы соединений дают вам массу преимуществ, но больше всего они решают проблемы

    <Ол>
  • Создание реального подключения к базе данных является дорогостоящим. Пул подключений всегда имеет несколько дополнительных подключений и дает вам одно из них.
  • В случае сбоя соединения пул соединений знает, как открыть новое
  • Очень важно: каждый поток получает свое собственное соединение. Это означает, что многопоточность обрабатывается там, где она должна быть: на уровне БД. БД суперэффективны и могут с легкостью обрабатывать параллельные запросы.
  • Другие вещи (например, централизованное расположение строк соединения JDBC и т. д.), но есть миллионы статей, книг и т. д.
  • Когда устанавливать соединение

    Где-то в стеке вызовов, инициированном вашим делегатом службы (doPost, doGet, doDisco и т. д.), вы должны установить соединение, а затем сделать правильные вещи и вернуть его в блоке finally. Я должен упомянуть, что главный архитектор C # однажды сказал, что вы должны использовать блоки finally в 100 раз больше, чем блоки catch . Более правдивые слова никогда не произносились ...

    Какой пул соединений

    Вы находитесь в сервлете, поэтому вы должны использовать пул соединений, предоставляемый контейнером. Ваш код JNDI будет полностью нормальным, за исключением того, как вы получаете соединение. Насколько я знаю, все контейнеры сервлетов имеют пулы соединений.

    В некоторых комментариях к ответам выше предлагается использовать определенный API-интерфейс пула соединений. Ваша WAR должна быть переносимой и «просто развернуть». Я думаю, что это в основном неправильно. Если вы используете пул соединений, предоставленный вашим контейнером, ваше приложение будет развернуто в контейнерах, которые охватывают несколько компьютеров, и все эти интересные вещи, которые предоставляет спецификация Java EE. Да, дескрипторы развертывания для конкретного контейнера должны быть написаны, но это EE-способ, мон.

    Один комментатор упоминает, что некоторые предоставленные контейнером пулы соединений не работают с драйверами JDBC (он упоминает Websphere). Это звучит совершенно надуманным и смешным, так что, вероятно, это правда. Когда такие вещи случаются, выбрасывайте все, что вы "должны делать" в мусор и делай что можешь. Это то, за что нам иногда платят :)

    Я бы использовал Commons DBCP . Это проект Apache, который управляет пулом соединений для вас.

    Вы просто получите свое соединение в doGet или doPost, выполните свой запрос и затем закроете соединение в блоке finally. (con.close () просто возвращает его в пул, но не закрывает его).

    DBCP может управлять таймаутами соединения и восстанавливаться после них. То, как вы в настоящее время делаете вещи, если ваша база данных отключается в течение какого-то периода времени, вам придется перезапустить приложение.

    Вы объединяете свои соединения? В противном случае вам, вероятно, следует уменьшить накладные расходы на открытие и закрытие ваших соединений.

    Как только это не удастся, просто оставьте соединение открытым до тех пор, пока это необходимо, как предположил Джон.

    Лучший способ, и я сейчас просматриваю Google для лучшего справочного листа, это использовать пулы.

    При инициализации вы создаете пул, содержащий X количество объектов SQL-соединения с вашей базой данных. Храните эти объекты в каком-то списке List, например, ArrayList. Каждый из этих объектов имеет частное логическое значение для isLeased, долгое время его последнего использования и соединение. Всякий раз, когда вам нужно соединение, вы запрашиваете соединение из пула. Пул либо даст вам первое доступное соединение, проверив переменную isLeased, либо создаст новое и добавит его в пул. Обязательно установите метку времени. Как только вы закончите с подключением, просто верните его в пул, который установит isLeased в false.

    Чтобы избежать постоянного подключения соединений к базе данных, вы можете создать рабочий поток, который будет периодически проходить через пул и видеть, когда в последний раз использовалось подключение. Если он достаточно длинный, он может закрыть это соединение и удалить его из пула.

    Преимущества использования этого состоят в том, что у вас не будет длительного времени ожидания, пока объект соединения не соединится с базой данных. Ваши уже установленные соединения могут быть использованы сколько угодно. И вы сможете установить количество подключений в зависимости от того, насколько загруженным будет ваше приложение.

    Вы должны держать соединение с базой данных открытым только столько, сколько вам нужно, что, вероятно, зависит от того, что вы делаете, в пределах ваших методов doGet / doPost .

    Объедините его.

    Кроме того, если вы работаете с необработанным JDBC, вы можете заняться чем-то, что поможет вам управлять подключением, PreparedStatement и т. д. Если у вас не очень жесткий "легкий вес" требования, например, использование поддержки Spring JDBC, значительно упростит ваш код, и вы не обязаны использовать любую другую часть Spring.

    Смотрите несколько примеров здесь:

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

    Пул соединений, связанный с источником данных, должен помочь.Вы можете получить соединение из источника данных в методе запроса сервлета (doget/dopost, и т. д).

    dbcp, c3p0 и многие другие пулы соединений могут сделать то, что вам нужно.При объединении соединений в пул вы можете объединить Statements и ReadedStatements;Кроме того, если вы используете среду READ HEAVY, как вы указали, вы можете кэшировать некоторые результаты, используя что-то вроде ehcache.

    БР,

    Обычно вы обнаружите, что открывать соединения по запросу проще в управлении. Это означает в методе doPost () или doGet () вашего сервлета.

    Открытие его в init () делает его доступным для всех запросов, и что происходит, когда у вас есть параллельные запросы?

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top