Технологии подключения к базе данных из JSP-страниц и сервлетов веб-приложений Java
Грибанова-Подкина Мария Юрьевна
кандидат физико-математических наук
доцент, Балашовский институт (филиал), ФГБОУ ВО «Саратовский национальный исследовательский
государственный университет им. Н.Г. Чернышевского»
412300, Россия, Саратовская область, г. Балашзв, ул. Карла Маркса, 29 И [email protected]
Статья из рубрики "Базы данных"
Аннотация.
Целью исследования является демонстрация многообразия решений по вопросу соединения с базой данных, включая описание разработанного класса контроллера подключения, а также различных способов создания пулов соединений на веб-сервере и серверах приложений. В статье рассматриваются практические вопросы использования технологии JDBC при построении веб-приложения Java. В приведенных примерах презентационный и бизнес-слой приложения разрабатываются с помощью JSP-страниц и сервлетов, база данных функционирует на платформе MySQL. Описываемые способы создания и настройки пула соединений приведены на примере веб-сервера ApacheTomcat и сервера приложений GlassFish. Вопрос оптимизации соединений с базой данных в приложениях Java остается открытым, несмотря на многообразие решений. В исследовании рассматриваются и предлагаются методы построения классов-коннекторов, различные способы создания пулов соединений, а также описываются результаты решения проблем, возникающих при реализации описанных методик. Приведена развернутая классификация способов соединения с базой данных.
Ключевые слова: GlassFish, MySQL, сервер приложений, веб-сервер, пул соединений, JDBC, база данных, веб-приложение, контроллер подключения, источник данных
DOI:
10.25136/2306-4196.2019.2.19589
Дата направления в редакцию:
11-07-2016
Дата рецензирования:
07-07-2016
Введение
Тенденции в разработке современного программного обеспечения таковы, что веб-
приложения начинают вытеснять традиционные десктопные приложения из многих сфер применения. Современные веб-приложения решают разнообразные задачи, возникающие в различных предметных областях и, как правило, опираются на взаимодействие с базами данных. Архитектура таких приложений является многослойной, и для стыковки слоев необходимы соответствующие компоненты. Для работы с базой данных в приложениях Java таким компонентом является технология JDBC, которая предоставляет ряд интерфейсов и классов, обеспечивающих данную функциональность.
Для работы с базой данных в Java используется интерфейс Connection , с помощью которого клиентское приложение осуществляет обращение к объектам базы данных, оправляя сообщения и получая результаты. Дескриптор соединения, являющийся объектом типа Connection , может быть получен двумя основными способами:
• с использованием класса DriverManager, когда устанавливается физическое соединение с базой данных;
• с использованием интерфейса DataSourse, когда связь с базой данных осуществляется посредством источника данных.
Интерфейс DataSourse был введен в JDBC 2.0 Optional Package API и позволяет обобщать спецификацию ресурса базы данных. В отличие от DriverManager, требующего подробного описания всех деталей соединения, DataSourse скрывает детали реализации, оперируя логическими именами.
Рассмотрим оба варианта создания дескриптора соединения с базой данных и области использования приведенных способов.
Подключение к базе данных
Начальный этап разработки веб-приложения, которое построено на взаимодействии с базой данных, включает в себя процесс подключения к базе данных. Этот процесс, основанный на использовании класса DriverManager , согласно технологии JDBC, включает в себя следующие моменты:
• загрузка драйвера JDBC для нужной базы данных;
• формирование строки подключения (JDBC-URL);
• создание подключения и получение его идентификатора.
Самым простым вариантом будет установка этого соединения в скрипте прямо на странице.
Существенным моментом при осуществлении подключения является возможность возникновения множества ошибок, которые нужно отслеживать. Поэтому весь код подключения должен быть заключен в защищенный блок.
В приведенном ниже фрагменте кода (см. листинг 1) на JSP-странице описаны также следующие объекты:
• типа Statement , определяющий предложение (запрос) к базе данных;
• типа ResultSet , представляющий собой результат запроса - курсор с выборкой.
Листинг 1. Код подключения к базе данных
ResultSet"^^slant.^ * from directors");
После подключения к базе данных и получения из нее результатов выборки всех данных из таблицы, можно вывести эти данные на странице. Таким образом, код JSP-страницы будет содержать два блока:
• блок подключения к базе данных;
• блок отображения или обработки данных.
Аналогично и для других JSP-страниц и сервлетов, которые будут подключаться к базе данных. Такая логика построения кода приводит к его неоправданно большому дублированию, а также сильно загромождает страницы. Не менее важен и тот факт, что создание соединения при каждом обращении к базе данных является неоптимальным в плане временных потерь на создание соединения, которые сравнимо больше того времени, которое затрачивается на обработку запроса или выполнение транзакции.
Для решения озвученных проблем на веб-сервере можно разместить специальный класс, который будет отвечать за соединение с базой данных.
Разработка и использование контроллера подключения
Итак, необходим один-единственный объект, который будет держать соединение с базой данных. Этот объект и станет контроллером подключения. Использование при разработке паттерна Singleton гарантирует, что у класса всегда будет только один экземпляр, и к нему будет предоставлена глобальная точка доступа.
Для реализации контроллера соединений с помощью рассмотренного паттерна, создаем обычный java-класс с названием ConnectBean .
Согласно принципам паттерна Singleton, определяем в классе закрытое статическое поле instance из того же класса ConnectBean , а также закрытый конструктор класса, который осуществляет подключение к базе данных. Дополнительно в классе необходимо описать поле типа Connection , которое будет хранить в себе идентификатор соединения.
Обеспечивает получение объекта класса метод getInstance (), который будет возвращать ссылку на объект, если он уже существует, или создавать объект в случае его отсутствия. Таким образом, будет гарантироваться единственность экземпляра класса-контроллера. Метод getConnection () будет возвращать идентификатор соединения (см. листинг 2).
Листинг 2. Описание класса контроллера подключения
private CoimectBean (} throws Exception {
Class . forPiame (dfciver) .newlnstance () ; > catch (ClassHotFojndException e> {
public зсаис synchronized ConnectBean getlnitince()
Теперь, когда обязанность по установке соединения с базой возложена на объект класса ConnectBean , можно значительно сократить скрипты на JSP-страницах. Для этого необходимо лишь получить экземпляр класса ConnectBean и применить к нему метод getConnection (). Ниже приведен код (см. листинг 3), где создается объект-запрос к базе данных на основе соединения из класса-синглтона ConnectBean .
Листинг 3. Измененный скрипт подключения к базе данных
Таким образом, контроллер подключения к базе данных значительно сокращает код на JSP-странице, позволяя достаточно простым способом получать идентификатор соединения в любом необходимом фрагменте. Предложенный способ соединения с базой данных оправдан при использовании в веб-приложениях небольшого масштаба с ограниченным числом пользователей. Он с успехом функционирует, например, в системах, описанных в -Ш и
Недостатком предложенного подхода является ограничение нагрузки на соединение: в случае обращения к одному соединению большого числа клиентов будет образовываться очередь, что снова приведет к потере производительности приложения. Решение этой проблемы возможно с помощью реализации менеджера соединений, который должен реализовывать следующие функции:
• наличие нескольких соединений с базой данных;
• учет свободных и использующихся соединений;
• управление процессом выдачи соединения клиенту и др.
Пример такого менеджера приведен в Идея заключается в том, что менеджер соединений оперирует с двумя списками: списком доступных и списком используемых подключений. При запросе соединения клиент либо получает его из списка доступных подключений, либо для него открывается новое соединение, которое переносится в
список используемых. После освобождения клиентом соединение снова возвращается в список доступных.
Фактически, представленная схема является упрощенным вариантом пула соединений. Использование пула соединений
Рассмотренные варианты управления соединениями с базой данных основывались на использовании класса DriverManager , который создавал соединения с помощью статического метода getConnection (). Альтернативным вариантом является использование интерфейса DataSourse .
Интерфейс DataSource предоставляет возможность получения соединения с базой данных, абстрагируясь от местоположения сервера СУБД и типа драйвера конкретного производителя. Объект типа DataSource может создаваться в приложении или на сервере. Доступ к нему осуществляется через службу Java Naming и Directory Interface (JNDI). Используя класс контекстаInitialContext , компонент приложения может найти нужный ресурс. Класс контекста InitialContext предоставляет доступ к окружению идентификации приложения. Следующий код показывает, как можно использовать объекты типа DataSource для соединений из JSP-страниц, развернутых в веб-сервере или сервере приложений J2EE (см. листинг 4).
Листинг 4. Соединение с базой данных, основанное на DataSource
DataSource ds= ¡DataSource") ctx. lookup ("java : comp/er.v/jdbc/rayTest" );
Текст java: comp/ env в составе параметра задает, что метод lookup должен осуществлять поиск ресурса в записях окружения компонента приложения (т.е. в списке имен ресурсов, задаваемых при развертывании). Текстjdbc/ myTest задает, что ресурс представляет собой источник данных JDBC под именем my Test . Естественно, что этот ресурс должен быть предварительно описан и развернут на веб-сервере или сервере приложений.
Однако обычная реализация интерфейса DataSource также позволяет устанавливать лишь одно соединение с источником данных, что приводит к тем же проблемам в потере производительности, которые были рассмотрены выше. При этом реализация интерфейса DataSourse позволяет использовать принципиально другой подход к оперированию соединениями, который основан на реализации пула соединений.
Концепция пула соединений основана на следующих положениях:
• наличие нескольких соединений с базой данных;
• управление процессом выдачи соединений клиентам: выдается свободное соединение, а при его отсутствии создается новое;
• управление процессом возврата соединения в пул;
• отслеживание длительно невостребованных соединений и их закрытие.
Таким образом, пул соединений берет на себя роль управления жизненным циклом соединений.
В Java имеется стандартизированная концепция пула соединений в JDBC. Дополнительные интерфейсы и все основные серверы приложений имеют реализации э тих инте рфе йс ов .
Рассмотрим решения для реализации пула соединений, предлагаемые основными серверами, на примере соединения с базой данных MySQL, которая доступна на локальном хосте по адресу localhost:3306/ test .
Веб-сервер Apache Tomcat предлагает следующее решение для создания пула:
1) объявление нового ресурса в контексте приложения - файл context. xml . Минимально необходимые настройки приведены на листинге 5.
Листинг 5. Настройка ресурса в файле context. xml
drive rCl as sName = z of. . шуз ql. ; db с . i ve::n url= 'jdbc :r.ysql: //localhost: 3306/test"
2) добавление ссылки на этот ресурс в дескриптор развертывания приложения web. xml (см. листинг 6).
Листинг 6. Настройка ресурса в файле web.xml
<res-ref-name>j dbc/ir.yTest</res-ref-name> <res-type>javax.sql.Data5ource</res-type>
<res-sharing-sccpe>5hareable</res-sliaring-sccpe>
После этих настроек пул соединений становится доступным для подключения к базе данных из JSP-страниц и сервлетов с помощью кода, приведенного на листинге 4. Исчерпывающая документация по настройке, развертыванию и использованию пула
соединение на сервере Apache Tomcat представлена в [4].
Настройка пула соединений в консоли администратора сервера приложений
Схема настройки и реализации пула соединений для серверов приложений состоит в следующем:
1. создание пула соединений;
2. создание ресурса, связанного с пулом соединений.
3. добавление ссылки на ресурс в дескриптор развертывания приложения web. xml .
Таким образом, в отличие от веб-сервера Apache Tomcat, необходима настройка двух элементов: и пула, и ресурса. Все серверы приложений имеют стандартизованное решение по этому поводу, которое реализуется с помощью консоли администратора. Рассмотрим его на примере сервера приложений GlassFish 4. Приведенный ниже способ
создания пула менее детально описан также в J51.
Информация о существующих пулах соединений находится в ветке Resources/ JDBC/ JDBCConnection Pools (см. рис. 1). Создание нового пула осуществляется на этой же
странице с помощью кнопки New .
С О I оса I h ost:484В/с о m m о n/i ndexjsf
*Horoe_ About... *
User: admin Domain: domainl Server: localhost
GlassFishf Server Open Source Edition
H Common Tasks ^ Domain
server (Admin Server) g|j Clusters
Standalone Instances ► HH Nodes [=| Applications
Lifecycle Modules |gg| Monitoring Data t Resources
► Concurrent Resources
► Connectors
► y JDBC ► Q JDBC Resources
JDBC Connection Pools
To store, organize, and retrieve data, most applications use relational databases. Java EE applications access relational databases through the JDBC API. Before an application can access a database, it must get a connection.
Pools (2)
tQ JDBC Connection Pools
Resource Type
Derby Pool j av ax. s ql. DataS ourc e org. apac h e. derby, j dbc. CI i entDataS ourc e _TimerPool j av ax. s ql. X ADataS ourc e org. apac h e. derby, j dbc. E m beddedX ADat aS ou ne e
Рисунок 1. Обзор пулов соединения в консоли администратора сервера приложений
GlassFish
Создается новый пул соединений в два этапа. На первом указывается имя пула, выбирается тип ресурса и поставщик базы данных (см. рис. 2). В приведенном примере выбран тип ресурса java.sql.ConnectionPoolDataSource и база данных MySQL.
Рисунок 2. Создание пула. Шаг 1
Тип ресурса выбирается, исходя из требований к транзакциям, и может быть следующим [б].
• javax.sql.DataSource - поддерживаются только локальные транзакции;
• javax.sql.XADataSource - поддержка глобальных транзакций;
• java.sql.ConnectionPoolDataSource - локальные транзакции, возможные улучшения производительности.
На втором этапе создания пула устанавливаются его основные и дополнительные свойства (см. рис. 3). К основным относятся, например, минимальный и максимальный
размер пула (количество соединений), время простоя, максимальное время ожидания соединения.
New JDBC Connection Pool (Step 2 of 2) I Previous I I Finish I I Cancel |
Identify the general settings for the connection pool. Datasource Classname or Driver Classname must be specified for the
* Indicates required field
TestPoolMySQL
j av ax. s qi. Con n ecti onP ool DataS ourc e My Sql
com rnysql.jdbc.jdbc2. optional. My sql Conn ecti on Pool DataSource T
I
Select or enter vendor-specific classname that implements the DataSource andforXADataSounce APIs
Driver Classname: т
Select or enter vendor-specific classname that implements the java.sql.Driver interface.
Ping: Enabled
When enabled, the pool is pinged during creation or reconfiguration to identify and warn of any erroneous values for Its attributes
Description:
Рисунок 3. Создание пула. Шаг 2
Из дополнительных свойств минимально необходимыми являются URL (JDBC-URL) базы данных, имя пользователя и пароль для подключения (см. рис. 4). Эти свойства могут быть установлены на этапе создания пула, либо изменены во время редактирования уже созданного пула.
Additional Properties (3)
m Ы | Add Property
Select Name ++ Value ++
□ URL j dbc: my sql: /Л ocal h ost: 330 6/test
В password root
a user root
Рисунок 4. Установка дополнительных свойств пула
После рассмотренных действий по созданию пула, он будет отображаться в общем списке пулов (см. рис. 5) и может быть доступен из любого приложения, разворачиваемого на сервере приложений.
JDBC Connection Pools
То store, organize, and retrieve data, most applications use relational databases. Java EE applications access relational databases through the JDBC API. Before an application can access a database, it must get a connection.
Pools (3)
u □V 1 □ 1 1 1 New... 1 Delete
Select Pool Name t+ Resource Type t+ Classname t+
В Derby Pool j av ax. s ql. DataS ounc e org. apac h e. derby, j dbc. CI i entDataS ou re e
□ TestPoolMySQL j av ax. s ql. Connecti on P ool DataS ource com. my sql. jdbc.jdbc2. optional. MysqlConnectionPoolDataS ource
в _TimerPool j av ax. s ql. X ADataS ourc e org. a pac h e. derby, j dbc. Em beddedX ADataSourc e
Рисунок 5. Список пулов
connection pool.
General Settings
Pool Name:
Resource Type:
Database Driver Vendor:
Datasource Classname:
Для доступа к пулу остается создать связанный с ним ресурс. Это делается в соседней ветке Resources / JDBC / JDBC Resources . При создании ресурса указывается его имя, связанный пул и дается описание ресурса (см. рис. 6).
New JDBC Resource | ок 11 cancel |
Specify a unique JNDI name that identifies the JDBC resource you want to create. The name must contain only alphanumeric, underscore, dash, or dot characters.
JMDI Name: * jdbc/myTest
Pool Name: TestPoolMySQL *
Use the JDBC Connection Pools page to create new pools
Description:
Status: i^i Enabled
Рисунок 6. Создание ресурса, связанного с пулом
Теперь можно добавлять ссылку на ресурсjdbc/myTest в дескриптор развертывания приложения (см. листинг 6) и осуществлять соединение с базой данных через пул с помощью скрипта, приведенного на листинге 4.
Альтернативные способы создания пула соединений для сервера приложений
Для рассмотренного сервера приложений GlassFish существуют альтернативные способы создания пула соединений. Например, возможно создание пула из командной строки операционной системы с помощью команды серверу GlassFish:
• команда asadmin create - jdbc - connection - pool создает пул соединений JDBC;
• команда asadmin create - jdbc - resource создает JDBC-ресурс, связанный с пулом соединений.
Пример команды по созданию пула соединений приведен ниже на листинге 7.
Листинг 7. Создание пула из командной строки
asadmin create-jdbc-connection-pool --datasourceclassname com.mysql.jbdc.jbdc2.optional.MysqlConnectionPoolDataSource --restype javax.sql.ConnectionPoolDataSource --property user=root:password = root:url=jdbc:mysql://localhost:3306/test TestPoolMySQL
Пример команды по созданию связанного с пулом ресурса приведен на листинге 8.
Листинг 8. Создание ресурса из командной строки
asadmin create-jdbc-resource --connectionpoolid TestPoolMySQL jdbc/myTest
В предложен способ создания пула в интегрированной среде разработки NetBeans средствами самой среды. С этой целью в приложении создается файл g lassfish-resources.xml с описанием пула. Для создания файла и описания конфигурации пула используется диалог создания файла Пул соединений JDBC из категории GlassFish (см. рис. 7).
Рисунок 7. Создание файла с описанием пула в среде NetBeans. Шаг 1
Далее необходимо указать название пула и строку подключения к базе данных, которую можно извлечь из существующего подключения, уже настроенного в среде (см. рис. 8), либо указать новую строку подключения.
Рисунок 8. Создание файла с описанием пула в среде NetBeans. Шаг 2
После этого достаточно выбрать имя класса источника данных, тип ресурса и задать свойства подключения (см. рис. 9).
Рисунок 9. Создание файла с описанием пула в среде NetBeans. Шаг 3
Создание связанного с пулом ресурса осуществляется также интерактивно с помощью вызова диалога создания файла Ресурсы JDBC из категории GlassFish . В настройках необходимо указать нужный пул и JNDI-имя ресурса (см. рис. 10).
Рисунок 10. Создание связанного с пулом ресурса в среде NetBeans. Шаг 3 Описанные действия ведут к созданию двух секций в файле настроек д lassfish-
resources.xml :
• секция jdbc-resource , соответствующая ресурсу, по которому будет осуществляться доступ к соединению;
• секция jdbc-connection-pool , описывающая пул соединений.
При этом, согласно ^^ пул и ресурс должны разворачиваться на сервере в процессе развертывания приложения. Однако в списке ресурсов и пулов сервера приложений они не отображаются и, соответственно, не являются доступными для приложений с помощью кода, приведенного в листинге 4. Эта проблема неоднократно поднималась в технической поддержке NetBeans [8,9], но до сих пор не исправлена. Выходом в сложившейся ситуации является поиск ресурса не в глобальном контексте java:comp/env , а в контексте приложения java:app (см. листинг 9).
Листинг 9. Подключение к базе данных с поиском ресурса в контексте приложения
DataSource ds= (DataSource} ctx. lookup ( :ava:app/ dbc/teatPoolMySOL1') ;
Это означает, что пул и ресурс разворачиваются, но не самостоятельно, а в структуре приложения. Доступ к ним может осуществляться в этом случае только из данного приложения.
Заключение
Рассмотренные и предложенные способы соединения с базой данных, осуществляемые JSP-страницами и сервлетами веб-приложений Java, можно классифицировать следующим образом:
• простое соединение на основе класса DriverManager;
• контроллер подключения на основе класса DriverManager, управляющий физическим соединением с базой данных;
• менеджеры соединений на основе класса DriverManager, управляющие несколькими физическими соединениями с базой данных;
• простое соединение на основе интерфейса DataSource, которое обращается к источнику данных по его логическому имени (JNDI), при этом физическое соединение с базой данных держит сам источник данных;
• пул соединений с базой данных, управляющий потоками соединения с базой данных, доступ к пулу осуществляется через связанный источник данных.
Приведенные способы создания и настройки пула соединений приведены на примере веб-сервера ApacheTomcat и сервера приложений GlassFish. Настройка пула соединений на сервере приложений может осуществляться в консоли администратора, из командной строки, а также средствами интегрированных сред разработки (в приведенном примере -NetBeans).
Дополнительно необходимо отметить, что в противовес «коробочным» реализациям пулов соединений от разработчиков серверов приложений существуют и альтернативные способы. Они представляют собой библиотеки пулов для Java, которые разрабатываются вендорами БД (например, Oracle-^10!) и сторонними поставщиками, где наиболее популярными являются DBCP^11^ от Apache Software Foundation, HikariCP-^12! и c3p0 Такое многообразие решений говорит об актуальности вопроса оптимизации соединений с базой данных в приложениях Java и позволяет констатировать, что задача создания
пула, отвечающего всем требованиям разработчика, до сих пор остается открытой. Библиография
1. Грибанова-Подкина М.Ю., Аннушкин А.В. Модель информационной системы учета движения товара в компьютерном магазине // Технические науки - от теории к практике: сб. ст. по матер. LVII междунар. науч.-практ. конф. № 4(52). Новосибирск: СибАК, 2016. С. 44-51.
2. Грибанова-Подкина М.Ю. UML-модель партионного учета товара для автоматизированной информационной системы // Программные системы и вычислительные методы. 2016. № 2. C. 111-123. DOI: 10.7256/23056061.2016.2.19271
3. Простейший Connection pool без DataSource в Java [Электронный ресурс]. URL: https://habrahabr.ru/post/229199/ (дата обращения: 30.06.2016)
4. Apache Tomcat 8 (8.0.36) - The Tomcat JDBC Connection Pool [Электронный ресурс]. URL: https://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html (дата обращения: 30.06.2016)
5. Хеффельфингер Д. Java EE 7 и сервер приложений GlassFish 4 / пер. с англ. А. Н. Киселева. Москва: ДМК Пресс, 2016. 331с.
6. Sun GlassFish Enterprise Server 2.1 Administration Guide [Электронный ресурс]. URL: https ://docs.oracle.com/cd/E19879-01/820-4335/ablip/index.html (дата обращения: 30.06.2016)
7. Создание простого веб-приложения с использованием базы данных MySQL [Электронный ресурс]. URL: https://netbeans.org/kb/docs/web/mysql-webapp_ru.html (дата обращения: 30.06.2016)
8. Bug 254192 - New File glassfish-resources.xml is created in WEB-INF and JSF application will not run [Электронный ресурс]. URL:
https://netbeans.org/bugzilla/show_bug.cgi?id = 254192 (дата обращения: 30.06.2016)
9. Bug 243034 - The file glassfish-resources.xml in project is not executed on Glassfish in order to install a jdbc pool [Электронный ресурс]. URL:
https://netbeans.org/bugzilla/show_bug.cgi?id = 243034 (дата обращения: 30.06.2016)
10. Connect to Oracle using a connection pool [Электронный ресурс]. URL: http://www.rgagnon.com/javadetails/java-0545.html (дата обращения: 30.06.2016)
11. The DBCP Component [Электронный ресурс]. URL: http://commons.apache.org/proper/commons-dbcp/ (дата обращения: 30.06.2016)
12. HikariCP [Электронный ресурс]. URL: https://brettwooldridge.github.io/HikariCP/ (дата обращения: 30.06.2016)
13. c3p0 - JDBC3 Connection and Statement Pooling [Электронный ресурс]. URL: http://www.mchange.com/projects/c3p0/ (дата обращения: 30.06.2016)