Содержание


Разработка c помощью Apache Derby -- тройной выигрыш

Разработка баз данных на Java при помощи Apache Derby, Часть 1

Подключение

Comments

Серия контента:

Этот контент является частью # из серии # статей: Разработка c помощью Apache Derby -- тройной выигрыш

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Разработка c помощью Apache Derby -- тройной выигрыш

Следите за выходом новых статей этой серии.

Введение в 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

В первом примере создайте пустое рабочее пространство для разработки и выполнения кода приложения базы данных. Сначала создайте новую папку и разверните в нее исходный файл, прилагаемый к данной статье. Перед компиляцией используйте команду 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) ;
            }
        }
    }
}

В коде примера сначала определяются две константы, содержащие имя 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-приложении.


Ресурсы для скачивания


Похожие темы


Комментарии

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

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