Как и в любой другой Java-ориентированной технологии, в J2EE взаимодействие с реляционными СУБД основывается на JDBC, а точнее, на JDBC версии 2.1 и выше.

JDBC как часть J2EE

Для понимания механизма взаимодействия WAS CE (WebSphere Application Server, Community Edition) c СУБД необходимо знать основы JDBC.

То, что интерфейс JDBC построен по драйверному принципу, известно всем. К сожалению, те фундаментальные возможности JDBC, которые и позволяют ему успешно взаимодействовать с другими технологиями в составе J2EE, знакомы немногим — большинство разработчиков используют JDBC исключительно в стиле создания приложений в архитектуре «клиент—сервер». Впрочем, так и было задумано авторами спецификации — многие важные вещи выполняются не «на сцене», а «за кулисами».

Несмотря на возможности, предоставляемые современными JDBC-драйверами, разработчикам J2EE для решения ряда задач необходимо поддерживать более тесное взаимодействие с соединениями БД, нежели это позволяет JDBC. Примером может служить необходимость координации глобальных (на уровне координатора объектных транзакций распределенной системы) и локальных (на уровне соединения JDBC) транзакций. Поскольку программист может самостоятельно вызывать методы API JDBC, в том числе и методы управления локальными транзакциями (такими, как setAutoCommit() или commit()), возникает опасность рассогласованного поведения при наличии глобальных транзакций.

Был найден следующий выход: такие операции, как создание и поддержка пула соединений, выбор нужного вида соединения, сопоставление соединения с контекстом глобальной транзакции, в большинстве случаев осуществляет не JDBC-драйвер, а специальный программный модуль в составе самого J2EE-сервера приложений. Собственно драйвер используется тогда, когда нужно получить физическое соединение с СУБД, а также для поддержки распределенных транзакций (XA-транзакций).

Пулы соединений в WAS CE

В данном случае функциональность пула соединений с БД вполне стандартная, а интерфейс объектов Java-реализации пула (точнее, пулов — с поддержкой распределенных транзакций или с поддержкой только локальных транзакций) объявлен на уровне спецификации J2EE. Это означает, что можно создать готовую реализацию пула соединений, а затем обеспечить доступ к ним из прикладных приложений (и/или серверов приложений). В J2EE такие открытые для взаимодействия с приложениями библиотеки реализуются с помощью ресурсных адаптеров, которые включены в стандартные модули J2EE, — со стандартными дескрипторами, правилами взаимодействия с другими модулями, формализованной процедурой развертывания на J2EE-сервере и т.д.

Важно понимать, что пул соединений при работе с WAS CE следует рассматривать как самостоятельный объект, сущность, которая сама по себе связана скорее с БД как таковой, нежели с приложением, взаимодействующим с этой БД.

Итак, создавать пул соединений (в виде RAR-архива) нужно только в том случае, если разработчика не устраивает готовая реализация, входящая в состав WAS CE. Однако и эту реализацию приходится настраивать на конкретную БД и конкретный режим работы с этой БД. Настройка заключается в том, что создатель нужного пула соединений берет в готовом виде универсальный RAR-файл, а XML-дескриптор с конкретными параметрами настройки для этого адаптера для выполнения развертывания на сервере создает сам.

Поскольку логика работы с пулом соединений в общем случае зависит не от вида базы данных, а от поддерживаемых видов транзакций и соединений, то в состав дистрибутива WAS CE 1.1 входит несколько реализаций пула соединений и управления транзакциями. Работа с ними со всеми происходит одинаково, поэтому для примеров будем использовать универсальную реализацию для поддержки локальных транзакций.

Данная реализация выполнена в виде стандартного ресурсного адаптера J2EE — модуля с расширением RAR. Этот файл имеет имя tranql-connector-1.1.rar и находится (вместе с другими реализациями пула соединений) в каталоге epository ranql ars. Как для всякого модуля, его развертывание на сервере требует наличия xml-дескриптора. В этом xml-дескрипторе и указываются все необходимые для нормальной работы пула параметры.

В первую очередь разработчику приложения, взаимодействующего с БД, необходимо определить, какова должна быть «область видимости» создаваемого пула соединений.

При разработке серверных приложений возможны два варианта:

  • Создание пула, доступного всем приложениям, выполняемым под управлением данного J2EE-сервера. Пул (в виде RAR-модуля) является отдельным приложением, развертываемым на сервере WAS CE. Развернутый пул доступен, пока работает сервер.
  • Создание пула, доступного только для одного приложения. В этом случае RAR-модуль пула соединений будет развертываться на сервере не как самостоятельный модуль (самостоятельное J2EE-приложение), а как один из модулей в составе EAR-приложения. Такой пул существует только во время работы этого приложения.

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

Использование JDBC-драйвера

Для работы с БД с применением WAS CE необходимо иметь соответствующий JDBC-драйвер. Сейчас наиболее популярны JDBC-драйверы так называемого четвертого типа. Они поставляются в виде jar-файлов.

WAS CE содержит JDBC-драйверы (либо обеспечивает помощь в их поиске, загрузке и настройке) для многих распространенных СУБД: DB2 (и бесплатная СУБД DB2 Express-C), FrontBase, Informix, JDataStore, MS SQL Server, MySQL, Oracle, PostgreSQL, Progress, Sybase и др.

Для работы с базами данных могут применяться и доступные ODBC-драйверы (через мост JDBC—ODBC).

Кроме того, в состав WAS CE входит встроенная СУБД Derby (это клон БД Cloudscape), которая создавалась в рамках открытого проекта.

Многие из перечисленных СУБД поддерживаются как в локальном, так и в XA-режиме, т.е. режиме с распределенными транзакциями.

Несколько слов о поддержке встроенной БД Derby. Она используется сервисами самой WAS CE и готова к работе сразу после установки WAS CE. Derby поддерживается в различных режимах, в том числе в режиме с XA-транзакциями. Поскольку она играет особую роль, консоль администратора в панели навигации (левая часть консоли) содержит специальный пункт Embedded DB. С помощью средств консоли (DBManager) пользователь может создавать новые БД, интерактивно создавать и выполнять SQL-операторы для выбранной БД Derby, а также получить список параметров настройки этой СУБД (DB Info).

В примере приложения, создаваемого для этой статьи, будет использоваться не Derby, а бесплатная версия СУБД DB2 — DB2 Express-C, которую можно загрузить с сайта IBM (http://www-306.ibm.com/software/data/db2/udb/db2express/download.html).

JDBC-драйверы (содержащие их jar-файлы) должны находиться в каталоге repository (точнее, в одном из его подкаталогов) каталога установки WAS CE. Например, JDBC-драйвер для Derby находится в каталоге epositoryorg.apache.derbyjars, а драйвер для DB2 Express-C — в каталоге epository com.ibm.db2jars. Здесь под имеется в виду каталог установки WAS CE.

Если разработчик хочет для создания и настройки использовать JDBC-драйвер, не входящий в комплект поставки WAS CE, то он должен поместить этот драйвер в подкаталог каталога epository. Обратите внимание, что эксперты консоли администратора WAS CE полагаются на определенное соглашение об именах для jar-файлов. В частности, имя jar-файла обязательно должно содержать номер версии и подверсии драйвера. Например, jar-файл для драйвера DB2 Express-C имеет имя db2jcc-8.2.jar, а jar-файл для одного из Derby-драйверов — derby-10.1.2.ibm.jar, причем номер версии отделяется от имени дефисом.

Создание пула с помощью консоли администратора

Если нужно создать пул соединений уровня сервера, т.е. пул, доступный для всех приложений этого сервера, то наиболее удобно сделать это с помощью консоли администратора, которая содержит специальный мастер (wizard) для решения этой задачи. Для перехода к нему в панели навигации консоли нужно выбрать пункт Database Pools. Пул соединений можно либо создавать с нуля (мастер Using the Geronimo database pool wizard), либо импортировать готовый пул, созданный при работе с другими серверами — JBoss или Weblogic. В данной статье мы рассмотрим создание пула соединений с DB2 Express-C.

На первом шаге при использовании данного мастера разработчик должен выбрать имя создаваемого пула и тип используемой БД:

Имя пула должно быть уникальным на сервере среди имен всех других ресурсов. Это имя появится в специфическом для WAS CE дескрипторе развертывания — там, где необходимо будет сопоставить выбранное разработчиком JNDI-имя и имя реального ресурса.

После выбора одного из поддерживаемых мастером типов БД нужно перейти к следующему этапу (нажав кнопку Next).

Имя класса драйвера определяет сам мастер, хотя пользователь может его изменить «вручную». Jar-файл, содержащий код драйвера, нужно выбрать из списка. Если в этом списке нет соответствующего драйвера, можно попробовать найти его и загрузить с помощью мастеров консоли (кнопка Download a driver).

Дальнейшие параметры зависят от того, как был сконфигурирован установленный экземпляр СУБД, к которому выполняется обращение.

Наконец, на последнем шаге работы с мастером разработчик окончательно формирует нужный URL (URL формируется на базе ранее введенных данных, но здесь его можно изменить) и задает параметры: минимальный (0 по умолчанию) и максимальный (10 по умолчанию) размер пула, время ожидания (в миллисекундах, 5000 мс по умолчанию) до возбуждения исключения в случае, когда пользователь запрашивает соединение, но свободных соединений в пуле нет, и время ожидания (в минутах, 15 мин по умолчанию) до удаления неиспользуемого соединения из пула и уменьшения его текущего размера.

После задания всех параметров имеет смысл проверить настройку пула — установить соединение с СУБД (кнопка Test Connection). Если все хорошо, появится страница с соответствующей информацией:

Теперь можно выполнить развертывание созданного пула на сервере (кнопка Deploy на шаге 4 или кнопка Skip test and deploy на предыдущем шаге). Полезной — особенно при создании пула «вручную», о чем речь пойдет в следующем разделе, — может оказаться кнопка Show Plan (или Skip Test an Show Plan на предыдущем шаге), с помощью которой отображается сгенерированный xml-дескриптор для развертываемого коннектора.

Создание пула «вручную»

Учитывая возможности, предоставляемые мастерами консоли администратора, термин «вручную» не надо понимать буквально. Под ним подразумевается создание xml-файла, содержащего текст дескриптора, и некоторые манипуляции с этим файлом.

Для создания пула соединений уровня сервера приложений или корректировки его параметров всегда имеет смысл использовать консоль оператора; при этом в явном создании xml-файла дескриптора нет необходимости. Разумеется, даже при создании пула уровня сервера можно поступить иначе — создать xml-дескриптор, а затем с помощью командной строки развернуть пул на сервере. Этот подход бывает удобен, например, при использовании нетривиальных командных файлов. Командная строка для выполнения такого развертывания может выглядеть так:

java -jar bin/deployer.jar deploy <имя_файла_дескриптора>.xml 


repository/tranql/rars/tranql-connector-1.1.rar

Данный вид командной строки подразумевает, что текущим каталогом является каталог установки WAS CE.

Явное создание xml-файла дескриптора и размещение его в EAR-архиве необходимо в случае создания пула соединений на уровне J2EE-приложения, а не сервера. Для создания такого пула нужно выполнить следующие действия:

  1. Создать файл дескриптора RAR-архива, реализующего пул. Имя xml-файла может быть произвольным.
  2. Поместить этот файл в корневой каталог EAR-архива J2EE-приложения.
  3. Поместить в корневой каталог архива (вместе с JAR- и/или WAR-модулями) RAR-архив реализации пула, например файл tranql-connector-1.1.rar из каталога /repository/tranql/rars/.
  4. Добавить в каталог META-INF EAR-архива специфический для WAS CE дескриптор J2EE-приложения, файл которого должен иметь имя geronimo-application.xml и который должен содержать примерно такой текст:

application-1.0 configId=?MyApplication?>



имя_RAR_файла.rar

имя_XML_дескриптора.xml



Теперь осталось только ознакомиться с кодом дескриптора пула соединений (его вид не зависит от области видимости пула — на уровне сервера или на уровне приложения).

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





xmlns="http://geronimo.apache.org/xml/ns/j2ee/connector-1.0">



com.ibm.db2/db2jcc/8.2/jar











javax.sql.DataSource







MyDatabaseSource





adminpassword





com.ibm.db2.jcc.DB2Driver





db2admin





jdbc:db2://localhost:50000/MYDEMODB









10

0















Обратить внимание стоит на следующее:
  • При создании реальных приложений необходимо изменить сгенерированное мастером имя создаваемой конфигурации, в нашем случае — console-db-pool-MyDatabaseSource.
  • Тег всегда должен иметь значение «javax.sql.DataSource».
  • В некоторых версиях мастер консоли игнорирует заданные интервалы тайм-аутов, что приводит к использованию значений по умолчанию. В этом случае разработчик может добавить недостающий фрагмент дескриптора «вручную»:



...



10

0

...



10000





30





  • В дескрипторе присутствует ссылка на ресурс (jar-файл) с использованием тега :

deployment-1.0?>

com.ibm.db2/db2jcc/8.2/jar

Обратите внимание на формат URI, а также на то, что относительный путь к файлу ресурса указан относительно подкаталога repository каталога установки WAS CE.

Тег в нашем примере можно было записать и так:


xmlns:dep=?http://geronimo.apache.org/xml/ns/deployment-1.0?>

com.ibm.db2

db2jcc

8.2

jar

Тег со значением «jar» можно не указывать — это значение по умолчанию.

Использование параметров пула соединений в дескрипторах J2EE-модулей

Поскольку пулы соединений предназначены только для того, чтобы J2EE-приложения любого вида могли с ними работать, то важнейшим элементом приложения, использующего БД, является установление связи между пулом и приложением.

Идеология создания J2EE-приложений требует, чтобы такая взаимосвязь возникала не на этапе написания программы, а на уровне настройки уже написанного приложения для конкретного заказчика. Другими словами, программист, пишущий Java-код, не может и не должен знать, с каким видом СУБД будут взаимодействовать создаваемые им компоненты или где находятся серверы БД. Программист работает с высокоуровневой моделью взаимодействия с СУБД: он получает (обычно с помощью JNDI) доступ к фабрике соединений, роль которой в JDBC играет интерфейс DataSource и производные от него интерфейсы, а затем — с помощью вызова метода getConnection() — устанавливает логическое соединение с сервером, которое потом используется для задания команд работы с данными. В JDBC для этого применяется SQL. После того как соединение использовано, программист логически разрывает его. Все остальные вопросы программиста интересовать не должны. Java-код не содержит никакой информации, относящейся собственно к СУБД, и изменение типа СУБД или URL ее используемого экземпляра не должно приводить к необходимости перекомпиляции Java-кода приложения.

Спецификация J2EE явно говорит, что настройкой приложения под требования конкретного заказчика занимается не программист, а отдельный специалист, так называемый deployer (от англ. deploy — разворачивать, настраивать). Он не имеет и не должен иметь доступ к Java-коду. Вместо этого он работает с xml-дескрипторами модулей, из которых строится J2EE-приложение.

Обычно обращения к пулам соединений с БД выполняются из модулей, которые содержат веб- или EJB-компоненты. Пул соединений трактуется как ресурс J2EE, что приводит к использованию тега в стандартных xml-дескрипторах.

Вместе с тем нужно отчетливо понимать, что информации в дескрипторах, структура которых задана J2EE-спецификациями, недостаточно для нормальной работы.

Начнем со стандартного дескриптора и тега :





xmlns:xsi=?http://www.w3.org/2001/XMLSchema-instance?

xsi:schemaLocation=?http://java.sun.com/xml/ns/j2ee

http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd?

version=?2.4?>



jdbc/MySource

javax.sql.DataSource

Container

Shareable



Наиболее интересным параметром является значение тега . Это имя, под которым ресурс зарегистрирован в службе имен JNDI.

По поводу реализации JNDI в WAS CE необходимо сказать несколько слов. Хранилищем информации в JNDI являются объекты, называемые «контекстами». Ближайшим аналогом контекста JNDI является каталог файловой системы.

Спецификации J2EE оговаривают два вида контекстов JNDI — локальные и глобальные. Кратко их отличие друг от друга можно описать так: в локальный контекст помещается определенная информация из xml-дескрипторов, в то время как глобальный контекст предназначен для хранения произвольной информации, для чего используется универсальный API. Реализация JNDI в WAS CE не поддерживает глобальные контексты (хотя в состав WAS CE входят и другие службы имен). Все контексты являются локальными. Спецификация J2EE вводит фиксированный «начальный» локальный контекст с именем java:comp/env. Имя, указываемое в теге , является именем ресурса в этом стандартном локальном контексте, т.е. полное имя нашего ресурса в JNDI относительно начального контекста службы имен будет java:comp/env/ jdbc/MySource. Часть имени jdbc задавать необязательно, хотя это принятый среди J2EE-разработчиков способ задания имени пула соединений (точнее, интерфейса dataSource).

Этого достаточно, чтобы задать стандартный дескриптор J2EE. О том, каким именно образом устанавливается соответствие между JNDI-именем и реальным ресурсом, спецификация J2EE не говорит ничего. Такое соответствие не зависит от реализаций J2EE-сервера, и именно поэтому в каждом конкретном случае возникает необходимость использования дополнительных, специфических дескрипторов.

Рассмотрим такой специфический дескриптор, именуемый в WAS CE «планом развертывания» (deployment plan).





xmlns=?http://geronimo.apache.org/xml/ns/web?

xmlns:naming=?http://geronimo.apache.org/xml/ns/naming?

configId=?webdb_app?>

...



jdbc/MySource

MyDatabaseSource



Здесь нас пока интересует только тег .

WAS CE поддерживает несколько форматов ссылки на ресурс. В любом из них всегда необходимо указывать значение тега . Это значение задает JNDI-имя в основном дескрипторе, с которым сопоставляется конкретный ресурс. Далее возможны варианты, и самый простой и распространенный — использование тега . Значение тега должно соответствовать уникальному имени ресурса в одном из модулей, представляющем собой коннектор Java и развернутом на данном сервере (соответствие устанавливается по значению тега коннектора).

Осталось сказать немного об имени файла, который должен содержать код дополнительного дескриптора. В абсолютном большинстве случаев используется фиксированное имя файла дескриптора, и этот файл включается в стандартный каталог соответствующего J2EE-модуля. Например, для веб-приложений таким стандартным каталогом WAR-архива является каталог WEB-INF, а стандартный и дополнительный дескрипторы имеют имена web.xml и geronimo-web.xml соответственно.

Альтернативные способы задания имени дополнительного дескриптора и размещения его в архиве приложения будут рассмотрены в следующей статье, посвященной созданию для WAS CE Web-приложений, работающих с базами данных.

Использование пула на уровне Java-кода

Использование развернутого на сервере пула выполняется стандартным для J2EE образом — программист по заданному в xml-дескрипторе модуля приложения имени (в нашем примере — веб-модуль) получает доступ к фабрике соединений, затем вызывает метод getConnection() и использует API JDBC для работы с данными:

...


Context envContext = (Context)initContext.lookup(?java:comp/env?);

DataSource ds = (DataSource) envContext.lookup(?jdbc/MySource?);

Connection con = ds.getConnection();

...

con.close();

* * *

Итак, WAS CE предоставляет разработчикам гибкий механизм для взаимодействия со всеми наиболее распространенными реляционными СУБД с поддержкой как однофазных, так и двухфазных транзакций.