Java, начинавшая свой путь как средство украшения Web-страниц, постепенно переходит в разряд ключевых технологий для построения сетей intranet и сложных корпоративных приложений. Это стало возможным благодаря появлению в Java средств для работы с базами данных, без которых невозможно обойтись в сложных корпоративных системах.

Варианты архитектуры

Чтобы понять, какую роль может выполнять Java-программа в работе с базами данных, необходимо вспомнить несколько архитектур, которые используются для построения сложных клиент-серверных систем. Мы не будем рассматривать случай одноуровневой системы клиент-сервер, так как этот вырожденный случай использования баз данных просто не требует применения Java. В более сложной двухуровневой архитектуре клиент-сервер можно написать на Java пользовательский интерфейс, который будет общаться с базой данных на удаленном сервере, например, с помощью SQL-запросов. При разработке такого клиентского ПО уже потребуются абстрактные средства Java для составления SQL-запросов, которые можно настроить на работу с различными базами данных. Есть два способа связи с БД: статический (JSQL) и динамический (JDBC). JSQL - это расширение языка Java за счет добавления в него элементов SQL.

Текст JSQL-программы уже не является текстом Java, но он может быть преобразован в него с помощью специальной программы, называемой JSQL-транслятором. Эта программа проверяет правильность составления SQL-запросов, соответствия типов переменных и SQL-процедур. Таким образом, при разработке программ с помощью JSQL ошибки выявляются еще на этапе компиляции. Кроме того, разработанные с помощью JSQL программы работают быстрее, они лучше отлажены и имеют меньший размер. Однако при использовании JSQL нет возможности менять SQL-запросы во время исполнения программы, впрочем, в большинстве случаев этого и не требуется.

JDBC, в отличие от JSQL, позволяет динамически определять SQL-запросы. Этот метод общения с базами данных строится на основе стандартной библиотеки, которая распространяется с JDK 1.1. JDBC определят набор Java-классов, с помощью которых можно обратиться к любой базе данных через специальные JDBC-драйверы. Такая архитектура является более гибкой, так как позволяет менять SQL-запросы уже во время работы программы. Однако JDBC не проверят правильность SQL-запросов, поэтому если в программе есть ошибки, то это может выясниться только во время ее выполнения. Очень часто логика приложения пишется на JSQL, а потом тексты JSQL преобразуются в JDBC как низкоуровневое средство общения с базами данных. В этом случае JSQL-транслятор проверяет правильность составления SQL-запросов, а тонкую настройку можно в случае необходимости произвести уже с помощью JDBC.

Следует отметить, что JDBC может работать как напрямую с базой данных, так и через промежуточный слой - сервер приложений. Однако для связи Java-приложений с базами данных можно вообще обойтись без прямого общения Java-программы с базой данных. Это возможно в трехуровневой архитектуре клиент/сервер. Если сервер приложений уже разработан и отлажен, то можно запросы из Java-программы передавать этому серверу, который и будет работать с базой данных. Дело в том, что сервер приложений, реализованный на Java, в большинстве случаев менее эффективен, чем, например, сервер на С++. Если же система строится по трехуровневой архитектуре клиент/сервер, то лучше не применять средства прямого общения Java-программ с базами данных, а обойтись просто удаленными вызовами С-программ, которые расположены на сервере приложений.

JSQL

Если в Java-программе используется ограниченный набор функций для работы с СУБД или же необходимо обеспечить надежную работу Java-приложения и базы данных, то в этом случае лучше всего подойдет JSQL. Если в Java-программе предусмотрен небольшой набор функций для работы с СУБД, то лучше оформить такую программу с помощью JSQL, который обеспечит соответствие типов и самих SQL-запросов еще на этапе ее написания. Пользователь просто не сможет составить неверный запрос и что-то повредить в базе данных. Кроме того, JSQL-транслятор оптимизирует работу Java-приложений по времени, что позволяет создать наиболее быструю реализацию программы и оптимизировать использование ресурсов системы.

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

Собственно, использование JSQL похоже на работу с прекомпилятором в С/С++. Даже выражения JSQL немного напоминают команды прекомпилятора С:

#sql { DELETE FROM TAB };

Этот оператор удаляет столбец из таблицы TAB. Более сложный пример программы на JSQL приведен во врезке "Пример Java-программ на JSQL и JDBC".

Вообще говоря, существуют SQL-расширения различных языков программирования - С, COBOL, FORTRAN, ADA. Однако JSQL имеет серьезные преимущества перед другими вариантами расширений, обусловленные свойствами самого языка Java. Перечислим некоторые из них.

  • Java самостоятельно занимается управлением памятью (например, с помощью "сборщика мусора"), что позволяет не заботиться об использовании памяти в программах JSQL.
  • Все Java-типы очень хорошо структурированы и имеют нулевое значение null, которое можно использовать для нулевого состояния - SQL Null.
  • Кросс-платформенные возможности Java обеспечивают легкую переносимость JSQL-программ. Впрочем, некоторые JSQL-трансляторы используют особенности конкретной базы данных и генерируют непереносимую Java-программу. Для обеспечения хорошей переносимости транслятор должен использовать только стандартные и абстрактные механизмы Java типа JDBC.
  • Java-приложения являются бинарно совместимыми на всех платформах, и поэтому написанное на Java приложение базы данных может работать в сложной гетерогенной сети на различных платформах без перекомпиляции.

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

    JDBC

    Стандартным решением для организации связи Java-приложений с базой данных является JDBC. Именно эта библиотека входит в комплект JavaBeans и поставляется в комплекте средств разработки JDK 1.1. Эта библиотека обеспечивает Java-программам универсальное средство для работы с СУБД. JDBC работает аналогично ODBC - универсальному механизму доступа к базам данных, разработанному компанией Microsoft. Собственно, вызовы методов JDBC могут преобразовываться в вызовы функций ODBC с помощью специального моста JDBC - ODBC. JDBC выполняет три основные функции работы с базами данных:

  • установление связи с СУБД;
  • передача базе данных SQL-запросов;
  • обработка полученных результатов.

    Архитектура JDBC подразумевает использование как минимум четырех частей: Java-приложения, которое вызывает методы JDBC; собственно компонента JDBC, который распределяет клиентские вызовы по соответствующим базам данных; драйвера JDBC, который поддерживает сеанс связи с конкретной базой данных, и, наконец самой базы данных. Если драйвер JDBC поставляется производителем базы данных, то Java-приложение может получить доступ к ней через механизм JDBC без посредников. Этот вариант JDBC позволяет работать в двухуровневой архитектуре клиент-сервер.

    Однако если JDBC-драйвера по каким-либо причинам нет, можно воспользоваться стандартными драйверами ODBC, используя специальный мост JDBC - ODBC. В результате обращение к базе данных из Java-приложения будет выполняться по следующей цепочке: Java-приложение - JDBC - мост JDBC - ODBC - драйвер ODBC - база данных. Собственно, мост больше всего подходит для корпоративной системы с трехуровневой архитектурой, так как для работы такой системы требуется промежуточный сервер, на котором работает ODBC. Еще один вариант использования JDBC в трехуровневой архитектуре - это когда Java-программа связывается с сервером приложений по стандартному протоколу, а серверная Java-программа преобразует вызовы в протокол, используемый определенной базой данных.

    Хотя SQL стандартизован, многие СУБД используют свои собственные расширения этого языка. Задействовать эти расширения в JDBC можно тремя способами: путем прямого использования расширения для каждой конкретной базы данных; с помощью специальных последовательностей, аналогичных тем, которые применяются в ODBC; посредством настройки приложений под конкретную базу данных через механизм получения некоторых сведений о СУБД. В первом случае приложения становятся непереносимыми на другую базу данных, но они будут наиболее полно использовать возможности конкретной СУБД. Этот метод хорош для написания отдельных модулей, каждый из которых рассчитан на работу с конкретной платформой. Специальные управляющие последовательности более тонко связывает работу Java-приложения с базой данных, однако они не позволяют использовать все возможности, предоставляемые производителем СУБД. Наиболее тонкой настройки, видимо, можно добиться, если написать для каждой базы данных набор соответствующих модулей. Выбор же конкретного модуля выполняется во время работы программы с помощью методов интерфейса DatabaseMetaData.

    В общем, JDBC предлагает полный набор необходимых низкоуровневых функций для связи с базами данных (см. врезку "Пакет java.sql"), который может быть использован другими приложениями или трансляторами JSQL. Следует отметить, что метод CallableStatement позволяет запускать внутренние процедуры СУБД, что весьма важно в тех случаях, когда пользователям запрещено напрямую изменять содержание базы данных, но разрешено работать с определенными функциями СУБД. Этот метод позволяет более точно настроить права доступа пользователей к базе данных.

    Очевидно, что оба метода установки связи между Java-программами и базами данных найдут применение у разработчиков. Все будет зависеть от требований, предъявляемых к Java-программам: можно выбрать максимально гибкий доступ к базе данных или надежную и устойчивую работу всей системы. Видимо, если приложение разрабатывается в расчете на Web, например, для предоставления сотрудникам компании доступа к определенным базам данных, то лучше всего использовать JDBC, как более гибкий и настраиваемый инструмент. Если же предполагается использовать Java-программы в качестве клиентов сложной системы, например, для организации работы банка, то, видимо, такие программы лучше писать на JSQL, чтобы уменьшить риск выхода системы из строя и обеспечить наиболее быстрый доступ к базе данных.


    Полезные ресурсы по работе Java с СУБД

    www.javasoft.com/jdbc/index.html - страница на сервере JavaSoft, посвященная JDBC;

    www.oracle.com - на этом сервере можно найти более подробную информацию о JSQL;

    www.javaworld.com - интерактивный журнал, посвященный различным аспектам Java-технологии;

    www.gamelan.com - каталог Java-ресурсов.


    Пример Java-программ на JSQL и JDBC

    Рассмотрим пример программ на JSQL и JDBC, в которых Java-приложение связывается с базой данных STUDENT и распечатывает из него некоторую информацию о студентах. Фрагмент такой программы, написанный на JSQL, выглядит следующим образом:

    #sql iterator Honors (String name,
    float grade);
    Honors honor;
    #sql (recs) honor =
    	{ SELECT STUDENT AS "name", SCORE AS "grade"
    	FROM GRADE_REPORTS
    	WHERE SCORE >= :limit
    	AND ATTENDED >= :days
    	AND DEMERITS <= :offences
    	ORDER BY SCORE DESCENDING };
    while (honor.next()) {
    	System.out.println( honor.name() + "has grade" + honor.grade() );
    }

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

    java.sql.PreparedStatement ps =
    	recs.prepareStatement(
    	"SELECT STUDENT, SCORE"
    	+ "FROM GRADE_REPORTS"
    	+ "WHERE SCORE >= ?"
    	+ "AND ATTENDED >= ?"
    	+ "AND DEMERITS <= ?"
    	+ "ORDER BY SCORE DESCENDING");
    ps.setFloat(1, limit);
    ps.setInt(2, days);
    ps.setInt(3, offences);
    java.sql.ResultSet honor =
    ps.executeQuery();
    while (honor.next()) {
    	System.out.println(honor.
    getString(1) + "has grade"
    + honor.getFloat(2));
    }

    Переменная recs содержит объект типа java.sql.Connection, который обеспечивает связь с соответствующей базой данных.

    За пределами обоих текстов остались функции, которые открывают сеанс связи с базой данных.


    Пакет java.sql

    Пакет java.sql содержит классы и интерфейсы JDBC. Имеются следующие типы интерфейсов:

    Driver - определяет методы как драйвера, так и менеджера драйверов JDBC;

    Connection - выбирает методы для создания сеанса связи с базой данных;

    DatabaseMetaData - устанавливает методы для получения сведений о базе данных, с которой работает приложение;

    Statement - методы для передачи SQL-запроса базе данных;

    PreparedStatement - аналогичен Statement, но сохраняет бинарные планы обслуживания запроса для дальнейшего использования;

    CallableStatement - обеспечивает выполнение хранимых в базе данных SQL-процедур;

    ResultSet - методы для обработки результата обращения к базе данных;

    ResultSetMetaData - методы получения информации о типах данных, хранящихся в ResultSet;

    В состав пакета входят следующие классы:

    Date - спецификация SQL-типа DATE;

    Numeric - спецификация SQL-типов DECIMAL и NUMERIC;

    Time - спецификация SQL-типа TIME;

    Timestamp - спецификация SQL-типа TIMESTAMP;

    DriverManager - управление JDBC-драйверами;

    DriverPropertyInfo - информация о JDBC-драйверах;

    Types - управление дополнительными SQL-типами.

    Кроме того, в состав пакета java.sql входят обработчики исключительных ситуаций DataTruncation, SQLException и SQLWarning.