Разработка c помощью Apache Derby -- тройной выигрыш: Разработка баз данных на Java при помощи Apache Derby, Часть 1

Подключение

Присоединяйтесь! Эта статья начинает серию по созданию Java™-приложений, работающих вместе с базой данных Apache Derby. В ней показано, как подключиться к встроенной базе данных Derby при помощи встроенного в Derby драйвера Java Database Connectivity (JDBC). В статье также содержатся сведения по метаданным базы данных и показано, как в Java-приложении правильно обрабатывать ошибки и предупреждения SQL, создаваемые Derby.

Роберт Бруннер , ученый-исследователь NCSA, старший преподаватель астрономии, Университет штата Иллинойс, г. Урбана-Шампейн

Роберт Дж. Бруннер (Robert J. Brunner) занимается научными исследованиями в Национальном центре по приложениям для суперкомпьютеров и является старшим преподавателем астрономии в университете штата Иллинойс, город Урбана-Шампейн. Автор нескольких книг и множества статей и практических руководств на различные темы.



06.06.2007

Введение в JDBC

Ранее в статьях данной серии различные понятия баз данных были представлены на примерах применения инструмента ij для подключения и взаимодействия с базой данных Apache Derby. Хотя, возможно, в настоящий момент это не очевидно, но использовалось Java-приложение, в котором интерфейс прикладного программирования (API) JDBC применялся для подключения и взаимодействия со встроенной базой данных Apache Derby. В следующих нескольких статьях будет показано, как повторно создать базовые функции инструмента ij при создании собственного Java-приложения. В этой статье описывается подключение к базе данных и обработка возможных ошибок и предупреждений базы данных.

Прежде чем приступить к созданию Java-кода, возможно, окажутся интересными некоторые сведения о сущности JDBC API. JDBC представляет собой официальный Java Database Connectivity API и применяется, начиная с версии 1.1 Java Development Kit. JDBC API включен в пакет java.sql. Если посмотреть внимательно, можно заметить, что API представляет собой в основном интерфейсы. В результате JDBC драйвер баз данных фактически создается разрабочиками базы данных (или сторонними разработчиками), которые должны предоставить Java-классы, реализующие эти интерфейсы. Дополнительные функциональные возможности содержатся в расширениях JDBC API, доступных в пакете javax.sql. В следующих нескольких статьях в основном будет описываться стандартный пакет JDBC, расширения будут рассмотрены позднее.

И последнее о JDBC: Соединение между Java-приложением и базой данных управляется драйвером JDBC. Изначально имелось четыре типа драйверов JDBC, различаемых по номеру: 1, 2, 3 или 4. Эти типы соответствуют различным методам взаимодействия Java-приложения с базой данных. Сегодня большинство драйверов, включая драйверы, используемые для подключения к базе данных Derby, представляют собой драйверы типа 4, то есть они написаны полностью на языке Java и преобразуют JDBC API непосредственно в протокол базы данных, заданный производителем. Для базы данных Derby это процесс несколько упрощается, поскольку пакет Derby также написан на языке Java!

Apache Derby и JDBC

Теперь, когда имеется представление об основах JDBC, можно приступить к подключению к встроенной базе данных Apache Derby при помощи языка программирования Java. Но сначала необходимо установить программное обеспечение базы данных Apache Derby, как это обсуждалось в первой статье данной серии. Если этот важный шаг еще не выполнен, просмотрите первую статью, загрузите и установите ПО Derby. После установки системы баз данных Derby для подключения к базе данных Derby можно воспользоваться примером программы, прилагаемой к данной статье, как это показано в листинге 1.

Листинг 1. Выполнение примера программы
rb$ mkdir derbyWork
rb$ cd derbyWork/
rb$ unzip ../derby9.zip 
Archive:  ../derby9.zip
  inflating: FirstConnect.java       
rb$ ls    
FirstConnect.java
rb$ javac FirstConnect.java 
rb$ java FirstConnect 

----------------------------------------------------
Database Name    = Apache Derby
Database Version = 10.1.2.1
Driver Name      = Apache Derby Embedded JDBC Driver
Driver Version   = 10.1.2.1
Database URL     = jdbc:derby:test
----------------------------------------------------
rb$ java FirstConnect
SQLWarning: State=01J01, Severity = 10000
Database 'test' not created, connection made to existing database instead.

----------------------------------------------------
Database Name    = Apache Derby
Database Version = 10.1.2.1
Driver Name      = Apache Derby Embedded JDBC Driver
Driver Version   = 10.1.2.1
Database URL     = jdbc:derby:test
----------------------------------------------------
rb$ ls
FirstConnect.class      derby.log
FirstConnect.java       test

Что делать, если программа не запускается?

Хотя этот первый пример подключения к базе данных прост, насколько это возможно, проблемы иногда все же возникают. При программировании на языке Java чаще всего проблема заключается в том, что необходимые файлы классов не находятся в папке CLASSPATH. Например, если после компиляции кода и попытки его выполнения выдается ошибка JDBC Driver org.apache.derby.jdbc.EmbeddedDriver not found in CLASSPATH, необходимо добавить файл derby.jar в папку CLASSPATH. Эта проблема обсуждалась в первой статье данной серии. Другие возможные ошибки -- компиляция исходного кода Java без использования инструмента javac или выбор неправильной папки.

В первом примере создайте пустое рабочее пространство для разработки и выполнения кода приложения базы данных. Сначала создайте новую папку и разверните в нее исходный файл, прилагаемый к данной статье. Перед компиляцией используйте команду ls для проверки, что в папке имеется только исходный код Java, описываемый в данной статье.

Далее при помощи компилятора Java создайте файл байткода Java, который будет исполняться Java Virtual Machine (JVM) на следующем этапе. Если исходный код скомпилирован успешно, байткод можно выполнить в JVM. Код вызывает метод main для класса FirstConnect, создающий выходные данные, аналогично представленному коду; если возникают проблемы, см. вкладку "Что делать, если программа не запускается?". Этот Java-код сначала создает базу данных test, а затем -- подключение к этой базе данных при помощи драйвера JDBC пакета Apache Derby. Для демонстрации возможности кода по правильной обработке ошибок и предупреждений SQL, можно еще раз выполнить код. При этом выводится предупреждение, что база данных не создана (посколько она уже существует), и стандартные сведения о базе данных и драйвере JDBC, которые отображались ранее.

Данный пример завершается еще одним отображением содержимого рабочей папки, показывая как скомпилированные файлы Java-классов, так и новые файлы базы данных. Последнее является важным: При использовании Apache Derby в качестве встроенной базы данных, по умолчанию файлы базы данных находятся в той же папке, что и код. Если требуется разместить их в другой папке, необходимо изменить JDBC URL для задания папки, в которой будут создаваться файлы базы данных. Этот вопрос в данной статье не рассматривается. Просмотрите руководство Derby Developer's Guide, доступное по ссылке в интерактивных руководствах, приведенной в разделе Ресурсы.


Подключение Java-приложения в базе данных Derby

Java-код, выполнение которого было показано в предыдущем разделе, является простым и подробно описан в оставшейся части статьи. В производственной среде разработка Java-приложений баз данных может оказаться сложной. Вместо их подробного описания, которое будет сделано в следующих статьях, в данной статье рассматривается один из основных способов установления подключения Java-приложения к встроенной базе данных Apache Derby. Как видно из листинга 2, для этого метода требуется драйвер JDBC, реализующий протоколы подключения.

Листинг 2. Использование JDBC для подключения к базе данных Derby
private static final String driver = "org.apache.derby.jdbc.EmbeddedDriver" ;
private static final String url = "jdbc:derby:test;create=true" ;
 
public static void main(String[] args) {
    Connection con = null ;
    DatabaseMetaData dbmd = null ;
        
    try {
        Class.forName(driver) ;
        con = DriverManager.getConnection(url);
       
       // Use the database connection somehow.
       
    } catch (SQLException se) {
        printSQLException(se) ;
    } catch(ClassNotFoundException e){
        System.out.println("JDBC Driver " + driver + " not found in CLASSPATH") ;
    }finally {
        if(con != null){
            try{
                con.close() ;
            } catch(SQLException se){
                printSQLException(se) ;
            }
        }
    }
}

Как насчет DataSource?

Для простоты в данной статье рассматривается исключительно подключение к встроенной базе данных Apache Derby при помощи встроенного в Derby драйвера JDBC. В качестве стандартного правила предпочтительным решением JDBC для подключения к базе данных является использование DataSource, позволяющего отделить сведения о подключении к базе данных, например, URL-адрес базы данных, класс драйвера, имя пользователя, пароль и имя базы данных. За счет отделения специальных сведений о подключении можно легко изменить эти параметры без необходимости изменения кода приложения баз данных. В следующих статьях будет рассмотрено использование DataSource с Derby; но основы JDBC проще понять на примере драйверов JDBC и DriverManager, а уже затем приступать к изучению DataSource.

В коде примера сначала определяются две константы, содержащие имя Java-класса для встроенного в Apache Derby драйвера JDBC и URL-адреса JDBC подключения к базе данных. Этот URL-адрес подключения должен уже быть знакомым, он использовался в предыдущих статьях с командой connect инструмента ij. Значение, назначенное driver, представляет собой полное имя класса встроенного драйвера.

Остальной код содержится в методе main ; в нем загрузчик классов по умолчанию в JVM используется для поиска и обработки ранее созданного класса driver, выполняемого при помощи метода Class.forname. Этот метод выполняет поиск файла класса для встроенного в Derby драйвера, который должен находиться в папке, указанной в CLASSPATH, а затем загружает этот файл в JVM. В процессе загрузки обрабатывается статический раздел класса, регистрирующий драйвер в JDBC объекте DriverManager.

DriverManager действует в качестве объекта-фабрики. Предоставляя URL-адрес базы данных, DriverManager возвращает подключение к базе данных при помощи соответстующего драйвера JDBC. Этот шаг выполняется в следующей строке кода, где при помощи ранее определенного URL-адреса запрашивается JDBC connection в DriverManager.

Несомненно, уже замечено, что запрос на подключение содержится в блоке try ... catch, и что метод close для подключения вызывается в блоке finally. Оба эти вопроса будут рассмотрены далее в этой статье в разделе "Если что-то не получается". Учитывая ограничения на объем, в данной статье невозможно полностью рассмотреть различные способы установления подключения к базе данных при помощи JDBC. Например, в данном примере не используется информация, связанная с безопасностью, такая как имя пользователя или пароль. В следующих статьях будут рассмотрены другие методы подключения к базе данных (см., например, врезку "Как насчет DataSource?"). Если нет возможности ждать выхода этих статей, просмотрите руководство разработчика Derby Developer's Guide, ссылка на которое находится в разделе Ресурсы данной статьи.

Метаданные базы данных

Если нет опыта работы с метаданными, это понятие может показаться странным. На самом деле все просто: Метаданные -- это данные, описывающие данные. Относительно базы данных метаданные описывают определенную базу данных, например, имя базы данных, номер версии или имя драйвера JDBC, используемого для подключения. Доступ к метаданным базы данных в JDBC выполняется при помощи вызова соответствующего метода из объекта DatabaseMetaData, как это показано в листинге 3.

Листинг 3. Работа с метаданными базы данных
DatabaseMetaData dbmd = null ;
dbmd = con.getMetaData() ;

System.out.println("\n----------------------------------------------------") ;
System.out.println("Database Name    = " + dbmd.getDatabaseProductName()) ;
System.out.println("Database Version = " + dbmd.getDatabaseProductVersion()) ;
System.out.println("Driver Name      = " + dbmd.getDriverName()) ;
System.out.println("Driver Version   = " + dbmd.getDriverVersion()) ;
System.out.println("Database URL     = " + dbmd.getURL()) ;
System.out.println("----------------------------------------------------") ;

Для доступа к соответствующим метаданным сначала из текущего JDBC Connection создается новый объект DatabaseMetaData, как это показано в предыдущем примере. Затем можно вызвать одну из многих функций метаданных, предоставляемых драйвером JDBC пакета Apache Derby (полный листинг см. в спецификкации JDBC, ссылка на которую имеется в разделе Ресурсы статьи). В данном примере извлекается имя и номер версии программы для базы данных, к которой выполняется доступ, имя драйвера JDBC и номер версии, используемой для доступа к базе данных, и полный URL-адрес JDBC, определяющий базу данных, к которой установлено подключение. Метаданные базы данных особенно полезны при разработке приложения баз данных, взаимодействующего с различными базами данных или драйверами JDBC. В этом случае метаданные можно использовать для определения функций отдельной базы данных и драйвера JDBC во время выполнения.


Если что-то не получается

Поскольку используется база данных Apache Derby, либо из предыдущих статей данной серии, либо созданную пользователем, то, несомненно, отображались предупреждения базы данных и ошибки базы данных. Учитывая важность информации, хранимой в базе данных, соответствующая обработка ошибок и предупреждений базы данных может оказаться необходимой для бизнеса. К счастью, выполняя упражнения так, как это описано в данном разделе, такая обработка выполняется просто. Первым шагом будет показано, как просмотреть информацию, предоставляемую приложению об ошибке в базе данных, как это показано в листинге 4.

Листинг 4. Код обработки ошибок
private static void printSQLException(SQLException se) {
    while(se != null) {
        System.out.print("SQLException: State:   " + se.getSQLState());
        System.out.println("Severity: " + se.getErrorCode());
        System.out.println(se.getMessage());            
        
        se = se.getNextException();
    }
 }

private static void printSQLWarning(SQLWarning sw) {
    while(sw != null) {
        System.out.print("SQLWarning: State=" + sw.getSQLState()) ;
        System.out.println(", Severity = " + sw.getErrorCode()) ;
        System.out.println(sw.getMessage()); 
        
        sw = sw.getNextWarning();
    }
}

Как показано в листинге 4, обработка SQL-исключений и предупреждений SQL выполняется аналогично. Класс SQLWarning наследуется из класса SQLException; но предупреждение SQL менее серьезно, чем SQL-исключение, поэтому лучше обрабатывать их раздельно. Эти две функции объявляются как private static, что позволяет вызывать их из метода main, а не из других классов. В рабочем коде это можно изменить в соответствии с требованиями программы.

В обеих функциях выполняется цикл по предупреждениям и исключениям. Это может показаться странным с точки зрения нормальной обработки ошибок, но когда дело доходит до программирования баз данных, приходится ожидать сюрпризов. Причина последовательности проста: События зачастую связаны в базе данных. Например, если при вставке нескольких строк в базу данных происходит сбой, обусловленный несоответствием типов данных столбцов или имен, то возможно получить несколько ошибок. Для правильной обработки всех этих ошибок необходимо иметь возможность связать исключения так, чтобы уведомлять код вызова обо всех проблемах в базе данных. В целях упрощения Apache Derby всегда размещает важные исключения в начале цепочки исключений.

Внутри цикла выполняется вывод информации об ошибках или предупреждениях. SQL-состояние представляет собой строку из пяти символов, соответствующих "Спецификации среды прикладного программирования (CAE) X/OPEN, Управление данными: SQL, спецификация SQL версии 2 или стандартные преобразования SQL99", позволяющую программе восстанавливать из определенной базы данных состояния ошибок. Первые два символа The SQL-состояния представляют собой значение класса, последние три -- значение подкласса. SQL-состояние со значением 00000 соответствует успешному выполнению, тогда как значение класса 01 указывает на состояния предупреждений, например, усечение данных. Код SQL представляет собой значение, соответствующее определенной базе данных.

Обработка SQL-исключений выполняется просто. В качестве контейнера для вызовов методов JDBC используется стандартный механизм Java try ... catch, как это показано в листинге 5.

Листинг 5. Перехват SQL-исключенийexceptions
try{
    // Execute a JDBC operation
} catch (SQLException se) {
    printSQLException(se) ;
}

Как показано в этом примере кода, обработка исключений SQL выполняется с помощью передачи объекта SQLException в ранее определенный метод printSQLException, обрабатывающий все отчеты об ошибках. Основная сложность обработки SQL-исключений заключается в соответствующем восстановлении ресурсов базы данных, например, подключения к базе данных. Эти ресурсы, например, подключение или курсоры базы данных, могут управляться вне JVM, выполняющей код базы данных приложений, поэтому приложение должно закрывать их в явном виде. Метод close объекта Connection может вызывать SQLException, поэтому разместите этот метод в блоке finally, гарантирующем, что Java-приложение будет выполнять попытки закрыть подключение к базе данных даже при возникновении ошибок.

С другой стороны, необходимо явно проверить все предупреждения SQL, поскольку они не распространяются при помощи стандартных механизмов обработки исключений. Для этого вызовите соответствующий метод getWarnings для объекта JDBC, как это показано в листинге 6.

Листинг 6. Проверка предупреждений SQL
SQLWarning swarn = con.getWarnings() ;

if(swarn != null){
    printSQLWarning(swarn) ;
}

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


Обобщим полученные навыки

До настоящего момента в данной статье обсуждались различные компоненты, необходимые для установления подключения к базе данных при помощи JDBC API из Apache Derby. Совместно эти компоненты предоставляют большую часть всех необходимых функций, как это можно увидеть в завершенном примере подключения, показанном в листинге 7.

Листинг 7. Завершенный пример кода
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.DatabaseMetaData;

public class FirstConnect {
    private static final String driver = "org.apache.derby.jdbc.EmbeddedDriver" ;
    private static final String url = "jdbc:derby:test;create=true" ;
    
    static void printSQLException(SQLException se) {
        while(se != null) {

            System.out.print("SQLException: State:   " + se.getSQLState());
            System.out.println("Severity: " + se.getErrorCode());
            System.out.println(se.getMessage());            
            
            se = se.getNextException();
        }
    }
        
    static void printSQLWarning(SQLWarning sw) {
        while(sw != null) {

            System.out.print("SQLWarning: State=" + sw.getSQLState()) ;
            System.out.println(", Severity = " + sw.getErrorCode()) ;
            System.out.println(sw.getMessage()); 
            
            sw = sw.getNextWarning();
        }
    }

    public static void main(String[] args) {
        Connection con = null ;
        DatabaseMetaData dbmd = null ;
        
        try {
            Class.forName(driver) ;
            con = DriverManager.getConnection(url);

            SQLWarning swarn = con. getWarnings() ;
            
            if(swarn != null){
                printSQLWarning(swarn) ;
            }
            
            dbmd = con.getMetaData() ;
            
            System.out.println("\n----------------------------------------------------") ;
            System.out.println("Database Name    = " + dbmd.getDatabaseProductName()) ;
            System.out.println("Database Version = " + dbmd.getDatabaseProductVersion()) ;
            System.out.println("Driver Name      = " + dbmd.getDriverName()) ;
            System.out.println("Driver Version   = " + dbmd.getDriverVersion()) ;
            System.out.println("Database URL     = " + dbmd.getURL()) ;
            System.out.println("----------------------------------------------------") ;
            
        } catch (SQLException se) {
            printSQLException(se) ;
        } catch(ClassNotFoundException e){
            System.out.println("JDBC Driver " + driver + " not found in CLASSPATH") ;
        }
        finally {
            if(con != null){
                try{
                    con.close() ;
                } catch(SQLException se){
                    printSQLException(se) ;
                }
            }
        }
    }
}

Этот класс -- все, что требуется для установления подключения при помощи JDBC к встроенной базе данных Apache Derby, и именно это представлено в примере программы, откомпилированной и выполненной в начале этой статьи. В основном новый код представляет собой включение пяти предложений импорта в верхней части кода программы. Хотя можно использовать файлы import java.sql.*, отдельный листинг для каждого предложения импорта четко представляет JDBC-объекты, используемые в приложении.

Это приложение включает функции обработки ошибок, показанные в листинге 4. Все операции с базой данных включены в отдельный блок try ... catch, включая операции с метаданными базы данных, представленные в листинге 3. Во многих приложениях баз данных такая тесная связь между кодом приложения базы данных и самой базой данных избегается для упрощения управления и обслуживания приложения и базы данных. С учетом встроенных функций базы данных Apache Derby связь между приложением и базой данных размыта, такое разделение не требуется задавать в жестком виде.

Заключение

В этой статье было показано, как создать Java-приложение, подключенное к встроенной базе данных Apache Derby. В этом процессе для подключения к базе данных используется драйвер JDBC типа 4 из проекта Apache Derby, затем из базы данных извлекаются метаданные и подключение к базе данных закрывается. Также был описан способ обработки в Java-приложении предупреждений SQL и SQL-исключений, которые могут создаваться Derby. Следующие статьи будут основаны на методах, представленных в данной статье, и посвящены выполнению запросов к базе данных Derby и обработке результатов в Java-приложении.


Загрузка

ОписаниеИмяРазмер
Derby SQL script for this articlederby9.zip1KB

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source, Information Management
ArticleID=229025
ArticleTitle=Разработка c помощью Apache Derby -- тройной выигрыш: Разработка баз данных на Java при помощи Apache Derby, Часть 1
publish-date=06062007