|  | Уровень сложности: средний Роберт Бруннер , ученый-исследователь NCSA, старший преподаватель астрономии, Университет штата Иллинойс, г. Урбана-Шампейн
03.05.2007 Полный обзор создания простого запроса к базе данных Apache Derby и способов обработки выбранных результатов. Для этого потребуется представить три новых класса JDBC: Statement, ResultSet и ResultSetMetaData. Будет показано, как использовать эти классы с JDBC-подключением к базе данных для быстрого и простого извлечения данных из БД Apache Derby в собственное™ Java-приложение.
Выполнение JDBC-запроса: обзор
JDBC API разработан на основе иерархии, в которой объект одного типа содержит объекты других типов. Например, создадим подключение к базе данных с помощью JDBC Connection, для отправки SQL-запроса к базе данных создадим объект JDBC
Statement из соответствующего объекта Connection. Хотя эта операция кажется логичной, она имеет важное
значение: Если подключение к базе данных по какой-либо причине закрыто, закрываются также все объекты базы данных,
содержащиеся в этой базе данных. Такая иерархия расшираяется еще на один уровень, поскольку доступ к результатам запроса
выполняется с помощью объекта ResultSet, находящегося в
соответствующем объекте Statement. Данная иерархия представлена
на рисунке 1.
Рисунок 1. Отношение включения JDBC-объектов
Хотя в данной статье этого не делается, но если повторно выполнить JDBC-запрос, любой основной объект ResultSet
используется повторно. Это означает, что необходимо полностью обработать результаты запроса перед повторным использованием
JDBC Statement, например, при повторном запросе к базе данных, иначе будут
потеряны результаты предыдущего запроса.
Для выполнения запроса к базе данных Apache Derby прежде всего необходимо правильно
инициализировать базу данных. Если упражнения данного учебного руководства выполняются после предыдущих статей данной серии, то,
вероятно, у вас уже есть база данных, которую можно использовать в этом занятии. В противном случае, или если
вам требуется начать с чистого листа, можно воспользоваться файлом сценария derby.build.sql
, показанным в листинге 1.
Листинг 1. Инициализация рабочего пространства Apache Derby
rb$ mkdir derbyWork
rb$ cd derbyWork/
rb$ unzip ../derby10.zip Archive: ../derby10.zip
inflating: derby.build.sql
inflating: FirstQuery.java
inflating: SecondQuery.java
inflating: ThirdQuery.java
rb$ java org.apache.derby.tools.ij < derby.build.sql > derby.build.out 2> derby.build.err
rb$ javac *.java
rb$ ls
FirstQuery.class ThirdQuery.class derby.build.sql
FirstQuery.java ThirdQuery.java derby.log
SecondQuery.class derby.build.err test
SecondQuery.java derby.build.out |
Как показано в листинге 1, сначала создается новая рабочая папка, а затем извлекается файл исходного кода,
прилагаемый к данной статье (см. раздел Downloads в конце данного руководства). Следующий шаг заключается в создании базы данных Apache Derby, должным образом
инициализированной, что можно легко сделать, выполнив SQL-сценарий из инструментального средства Apache Derby ij. Наконец, выполняется компилирование трех прилагаемых
файлов Java с исходным кодом. Хотя результаты не представлены в явном виде (некоторые из них представляют собой довольно объемный вывод данных), можно
выполнить каждое из этих Java-приложений, например, с помощью ввода в командную строку java FirstQuery
. В остальной части данного руководства представлен исходный код для каждого из
этих трех примеров.
Выполнение запроса
Как было показано в предыдущем разделе, выполнение запроса к базе данных включает три основных понятия:
- Подключение к базе данных;
- Предложение запроса;
- Результаты запроса.
Для использования этих объектов
сначала необходимо импортировать их в приложение (см.
листинг 2.
Листинг 2. Запуск приложения JDBC-запроса
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.sql.ResultSet;
public class FirstQuery {
private static final String driver = "org.apache.derby.jdbc.EmbeddedDriver" ;
private static final String url = "jdbc:derby:test" ;
private static final String qry =
"SELECT itemNumber, price, stockDate, description FROM bigdog.products" ;
|
 |
Явные запросы: Лучшие методы
Как правило, создавать запросы к базам данных следует в явном виде. Избегайте использования запросов к столбцам без названий,
использующих предложение SELECT *, при этом создается слабая
связь между приложением и основной базой данных. При изменениях в базе данных,
например, переименовании столбца, изменении типа данных столбца или при добавлении или удалении столбцов
приложение будет работать, но результаты могут быть ложными. Перечисление столбцов в явном
виде сводит к минимуму возможность для такого типа ошибок, поскольку код действует в соответствии с ожиданиями,
если только запрашиваемые столбцы не были изменены. В случае их изменения код формирует
сообщение об ошибке, явно информируя разработчика о проблеме.
|
|
Фрагмент кода в листинге 2 сначала в явной форме импортирует все необходимые классы Java,
а затем определяет несколько важных констант, которые будут использоваться в оставшейся части создаваемой программы
запросов к базе данных. Большая часть кода должна быть знакома, ее можно было видеть в предыдущем
руководстве данной серии. Новые фрагменты кода представляют собой явное включение предложений import для JDBC-интерфейсов Statement и ResultSet
и строку запросов, которая выполняется далее в программе. Этот запрос содержит в явном виде список из
четырех столбцов в таблице bigdog.products и представляет собой лучший метод
(см. врезку Явные запросы). Такой порядок позволяет устранить различные потенциальные ошибки, возможные в случае
неожиданного изменения основной базы данных.
Операции, необходимые для выполнения запросов к базе данных из Java-приложения,
относительно просты, как это показано в листинге 3, представляющем метод doQuery длля программы FirstQuery.java. Обратите внимание, что сигнатура метода включает
предложение throws SQLException, указывающее, что любое SQL-исключение, сформированное из этого метода, должно обрабатываться кодом вызова. (Правильное выполнение обработки представлено в листинге 4.)
Листинг 3. Выполнение запроса к базе данных
static void doQuery(Connection con) throws SQLException {
SQLWarning swarn = null ;
Statement stmt = con.createStatement() ;
ResultSet rs = stmt.executeQuery(qry) ;
while (rs.next()) {
System.out.println("Item Number: " + rs.getString("itemNumber")) ;
System.out.println("Item Price: " + rs.getString("price")) ;
System.out.println("Stock Date: " + rs.getString("stockDate")) ;
System.out.println("Description: " + rs.getString("description") + '\n') ;
swarn = rs.getWarnings() ;
if(swarn != null){
printSQLWarning(swarn) ;
}
}
rs.close() ;
stmt.close() ;
}
|
В методе doQuery сначала создается новый JDBC-объект Statement с помощью метода createStatement объекта Connection
. Метод executeQuery объекта Statement используется
для отправки строки запроса в базу данных Apache Derby, где запрос выполняется. Доступ к результатам запроса
в Java-программе выполняется с помощью реализации ResultSet,
предоставляемой встроенным пакетом JDBC-драйвера Apache Derby.
Интерфейс ResultSet предоставляет различные способы доступа к
данным, возвращаемым запросом. В методе doQuery используется
метод итераций, посредством которого метод next просматривает все строки данных, полученных в результате выполнения запроса. Изначально этот итератор позиционируется перед первой строкой, чтобы после его первого вызова
итератор указывал на первую строку. При каждом выполнении цикла while
выполняется доступ к следующей строке набора полученных данных, и так до достижения последней строки. После обработки
последней строки итератор принимает значение null, поскольку выполнено
перемещение за последнюю строку; выполнение цикла прерывается.
В пределах цикла осуществляется доступ к четырем столбцам каждой строки с помощью метода getString объекта ResultSet, этот метод
извлекает значение столбца в виде Java-объекта String, поэтому можно выводить значения строки
непосредственно. Метод getString может обеспечивать доступ к столбцам двумя способами: с помощью
порядкового числа столбца в запросе или с помощью имени столбца. Например, в
предыдущем запросе методе getString(1) эквивалентен методу getString("itemNumber"). Как обычно, явное выражение является лучшим методом и
обычно предпочтительнее, поскольку позволяет уменьшить вероятность скрытых ошибок в
приложении. Кроме того, доступ к столбцам начинается с 1, а не с 0, что также может стать источником
проблем. То есть еще один стимул явного задания.
Хотя маловероятно, что будут сгенерированы все предупреждения, метод doQuery явно проверяет новые предупреждения в объекте ResultSet после доступа к новой строке. Это
необходимо, поскольку предыдущие предупреждения объекта ResultSet удаляются при
выполнении доступа к новой строке. В этом методе так делать не требуется, но аналогичным способом можно проверить SQL-предупреждения
в объекте Statement.
Для использования метода doQuery необходимо установить подключение к
базе данных и вызвать метод из блока try ... catch, как
это показано в листинге 4.
Листинг 4. Вызов метода doQuery
public static void main(String[] args) {
Connection con = null ;
try {
Class.forName(driver) ;
con = DriverManager.getConnection(url);
SQLWarning swarn = con.getWarnings() ;
if(swarn != null){
printSQLWarning(swarn) ;
}
doQuery(con) ;
} catch (SQLException se) {
printSQLException(se) ;
}
...
|
Как видно, с помощью инкапсуляции кода выполнения запроса в отдельном методе требуется только
одно изменение метода main кода подключения к базе
данных, представленного в предыдущем
учебном руководстве. После установления подключения к базе данных
и выполнения проверки возможных SQL-предупреждений вызовите метод doQuery, обрабатывающий все детали
запроса. В оставшейся части данного руководства изменим логику в методе doQuery для более подробного представления выполнения запросов select из
Java-программ к базе данных Derby.
Извлечение типов данных
В предыдущем разделе было показано, как выполнять запрос и извлекать данные в виде строк символов,
что идеально подходит для вывода или печати данных. Но гораздо чаще
к данным требуется применить бизнес-логику, для которой требуется извлечь данные в
соответствующем типе данных. Например, может потребоваться извлечь значение price
в виде цифровой денежной единицы, а stockDate -
в виде даты.
К счастью, JDBC API предоставляет методы извлечения данных
в виде соответствующих типов данных. Формально, правила соответствия типов довольно длинные, но поскольку
база данных Apache Derby создана на языке Java, соответствие типов значительно упрощается. Полное
описание синтаксиса можно найти в справочном руководстве по Apache Derby, указанном в разделе Ресурсы данного учебного руководства. Обычно ожидается соответствие типов,
показанное в листинге 5, где представлен метод doQuery для
программы SecondQuery.java.
Листинг 5. Соответствие типов
static void doQuery(Connection con) throws SQLException {
int itemNumber = -1 ;
BigDecimal price = null ;
Date stockDate = null ;
String description = null ;
BigDecimal threshold = new BigDecimal(40.00) ;
SQLWarning swarn = null ;
Statement stmt = con.createStatement() ;
ResultSet rs = stmt.executeQuery(qry) ;
while (rs.next()) {
itemNumber = rs.getInt("itemNumber") ;
price = rs.getBigDecimal("price") ;
stockDate = rs.getDate("stockDate") ;
description = rs.getString("description") ;
swarn = rs.getWarnings() ;
if(swarn != null){
printSQLWarning(swarn) ;
}else{
if((itemNumber < 6)&&(price.compareTo(threshold) > 0)){
System.out.println("Item Number: " + itemNumber) ;
System.out.println("Item Price: " + price) ;
System.out.println("Stock Date: " + stockDate) ;
System.out.println("Description: " + description + '\n') ;
}
}
}
rs.close() ;
stmt.close() ;
} |
В данном примере кода показан измененный метод doQuery, который теперь
извлекает результаты запроса в соответствующие типы данных. Столбец price
извлекается как тип данных java.math.BigDecimal, столбец
stockDate - как тип данных java.sql.Date. Хотя в коде, представленном на данном листинге, это не показано (это
только часть полного исходного кода файла SecondQuery.java), необходимо включить
соответствующие предложения import, чтобы обеспечить возможность использования в программе данных двух
классов.
В новой реализации метода doQuery выполняется цикл по
строкам набора результатов запроса, но теперь данные каждого столбца извлекаются в соответствующий
тип данных. Результаты можно выводить как и ранее, но теперь можно выводить только те строки, в которых значения
столбца itemNumber меньше 6, а значение price меньше заданного порогового значения (в данном примере меньше US$40,00). ResultSet может представлять собой сложный объект с множеством важных методов. Как будет показано в следующем
разделе, объект ResultSet имеет собственные метаданные, доступ к которым возможен с помощью
объекта ResultSetMetaData.
Использование метаданных запроса
Два предыдущих Java-приложения создавали длинные листинги результатов
запроса, даже если было выбрано всего несколько строк. Ранее в данной серии учебных руководств инструментальное средство
Apache Derby ij использовалось для выполнения операций с базами данных (оно также
использовалось в начале данного руководства для выполнения встроенного SQL-сценария). Средство ij предоставляет отлично отформатированный вывод результатов запроса, который также можно получить
с помощью объекта ResultSetMetaData и отформатированного предложения
печати, как это показано в листинге 6, представляющем метод doQuery
для программы ThirdQuery.java.
Листинг 6. Выполнение запроса с форматированием
static void doQuery(Connection con) throws SQLException {
int itemNumber = -1 ;
BigDecimal price = null ;
Date stockDate = null ;
String description = null ;
int numRows = 0 ;
String line = "------------------------------------" ;
BigDecimal threshold = new BigDecimal(40.00) ;
SQLWarning swarn = null ;
Statement stmt = con.createStatement() ;
ResultSet rs = stmt.executeQuery(qry) ;
ResultSetMetaData rsmd = rs.getMetaData() ;
System.out.printf("%-11s|", rsmd.getColumnName(1)) ;
System.out.printf("%-8s|", rsmd.getColumnName(2)) ;
System.out.printf("%-10s|", rsmd.getColumnName(3)) ;
System.out.printf("%-40s\n", rsmd.getColumnName(4)) ;
System.out.println(line + line);
while (rs.next()) {
itemNumber = rs.getInt("itemNumber") ;
price = rs.getBigDecimal("price") ;
stockDate = rs.getDate("stockDate") ;
description = rs.getString("description") ;
swarn = rs.getWarnings() ;
if(swarn != null){
printSQLWarning(swarn) ;
}else{
numRows ++ ;
System.out.printf("%-11s|", itemNumber) ;
System.out.printf("%-8s|", price) ;
System.out.printf("%-10s|", stockDate) ;
System.out.printf("%-40s\n", description) ;
}
}
System.out.println("\n" + numRows + " rows selected") ;
rs.close() ;
stmt.close() ;
}
|
В данном примере извлекаются метаданные для заданного объекта ResultSet с помощью объекта ResultSetMetaData. Хотя в данном листинге кода это не
показано, необходимо импортировать интерфей ResultSetMetaData,
представленный в прилагаемом файле исходного кода программы ThirdQuery.java. Эти метаданные содержат множество полезной информации, позволяющей
сделать собственное Java-приложение более удобным для работы с базами данных. Такая универсальность обычно не является необходимой для
Java-приложения, работающего с базой данных Apache Derby, поскольку тесная связь часто существует
между Java-приложением и встроенной базой данных Apache Derby, которая сама является
Java-приложением. Если требуется выполнить произвольную обработку, то для SQL-команд, как и для средства Derby ij,
важным является наличие доступа к этим метаданным.
Другое главное новшество в данном примере заключается в использовании форматированного вывода. Если раньше это не было
показано, теперь форматированное предложение print применяет строку формата к последующим данным для
создания форматированного вывода. В этом случае ограничьте длину каждого отображаемого
столбца и вставьте символ вертикальной черты (|) для разделения столбцов с целью имитация вывода,
создаваемого инструментом ij. Например, "%-11s|"
означает вывод символьной строки, ограниченной 11 символами, за которыми следует вертикальная черта. Знак "минус" означает выравнивание строки по левому краю.
Заключение
В данном учебном пособии было показано, как выполнять запросы к базе данных и обрабатывать результирующие наборы данных с
использованием трех примеров исходного кода Java. В первом примере выполнено подключение к
базе данных, выполнен запрос, результаты запроса выведены на экран. Во втором примере результаты
извлекались в соответствующих типах данных Java, а затем отфильтровывались
перед выводом на экран. Наконец, метаданные
результатов запроса использовались для вывода отформатированных результатов запроса аналогично способу, применяемому инструментальным средством
Apache Derby ij. В следующем учебном руководстве данной серии будет показано, как
применять методы извлечения данных, представленные в данном руководстве, для изменения данных в
базе данных Apache Derby.
Загрузка | Описание | Имя | Размер | Метод загрузки |
|---|
| Derby SQL script for this article | derby10.zip | 4KB | HTTP |
|---|
Ресурсы Научиться
- Оригинал статьи Developing with Apache Derby -- Hitting the trifecta: Java database development with Apache Derby, Part 2;
- Просмотрите некоторые связанные руководства данной серии:
- Первое учебное руководство в данной серии
"Разработка с помощью Apache Derby - тройной выигрыш: Введение в Apache Derby" (сайт developerWorks, февраль 2006 г.)
знакомит читателей с базой данных Apache Derby и содержит основные сведения по различных аспектам данной серии;
- Второе учебное руководство в данной серии
"Разработка с помощью Apache Derby - тройной выигрыш: Разработка баз данных Java с помощью Apache Derby, часть 1" (сайт developerWorks, март 2006 г.),
знакомит читателей с инструментальным средством ij и показывает, как его использовать для подключения к базе данных Apache Derby;
- Червертое учебное руководство в данной серии
"Разработка с помощью Apache Derby - тройной выигрыш: Разработка баз данных Java с помощью Apache Derby, часть 3
" (сайт developerWorks, май 2006 г.) знакомит читателей с понятием выполнения SQL-сценариев с Apache Derby. В руководстве показано, как
вставлять данные в таблицы базы данных Derby с помощью SQL-предложения
INSERT;
- Пятое учебное руководство в данной серии
"Разработка с помощью Apache Derby - тройной выигрыш: Разработка баз данных Java с помощью Apache Derby, часть 4
" (сайт developerWorks, июнь 2006 г.) знакомит читателей с понятием SQL-запрос. В руководстве показано, как извлекать данные из
базы данных Derby с помощью SQL-предложения
SELECT;
- В девятом учебном руководстве данной серии
"Разработка с помощью Apache Derby - тройной выигрыш: Разработка баз данных Java с помощью Apache Derby, часть 1
" (сайт developerWorks, декабрь 2006 г.) показано, как установить подключение к базе данных Derby из Java-программы.
- Доступ к различным Интернет-проектам Apache Derby: инструкции с подробной информацией об использовании баз данных Derby;
- Узнайте, как
загрузить и установить Apache Derby в данном учебном руководстве проекта Derby;
-
См. раздел Справочное руководство разработчика
Apache Derby содержит массу полезной информации, включая сопоставление типов, указывающее
допустимые преобразования между SQL
типами данными и соответствующими типами данных Java;
- Узнайте, как использовать
JDBC API на
официальном Web-сайте JDBC;
- Посетите раздел проекта Apache Derby сайта developerWorks; вы найдете статьи, практические руководства и другие ресурсы, которые помогут вам начать пользоваться Derby уже сегодня;
- Подробная информация о IBM® Cloudscape™
, которая построена на базе кода Apache Derby;.
- Следите за Техническими событиями и передачами web-вещания на сайте developerWorks;
- Просмотрите все статьи, посвященные Apache и бесплатные практические руководства по Apache, которые доступны в разделе Open source сайта developerWorks;
- Просмотрите книги по этой и другим техническим темам в книжном магазине Safari;
- Посетите Web-сайт института управления ИТ (раздел Open source zone сайта developerWorks: Вы найдете много дополнительных обучающих материалов, инструментов и проектов, которые помогут разрабатывать приложения по методикам с открытым исходным кодом и использовать их с продуктами IBM;
Получить продукты и технологии
Обсудить
Об авторе  | |  | Роберт Дж. Бруннер (Robert J. Brunner) занимается научными исследованиями в Национальном центре по приложениям для суперкомпьютеров и является старшим преподавателем астрономии в университете штата Иллинойс, город Урбана-Шампейн. Автор нескольких книг и множества статей и практических руководств на различные темы. |
Выскажите мнение об этой странице
|  |
Cloudscape, IBM и IBM (логотип) являются зарегистрированными торговыми марками корпорации IBM в США и/или других странах. Java является зарегистрированной торговой маркой компании Sun Microsystems в США и/или других странах. Другая компания, продукт или название услуги могут быть торговыми марками или знаками обслуживания, принадлежащими иным физическим или юридическим лицам. IBM обладает всеми авторскими правами касательно информации, расположенной на developerWorks. Использование информации приведенной на этом ресурсе без явного письменного разрешения от IBM или первоначального автора запрещены. Если Вы желаете использовать информацию с developerWorks, пожалуйста воспользуйтесь регистрационной формой для того, чтобы связаться с нами запрос на использование материалов developerWorks Россия. |