ResultSet содержит все строки, удовлетворяющие условиям в SQL-выражении
и предоставляет доступ к данным в этих строках посредствеом набора
get-методов, которые организуют доступ к колонкам текущей строки.
Метод ResultSet.next используется для перемещения к следующей
строке ResultSet, делая ее текущей.
Набор данных результата (result set) является таблицей с заголовками колонок
и соответствующих значений, возвращенных запросом. Например, если мы имеем запрос
SELECT a, b, c FROM Table1, то набор результата будет в следующей форме:
a b c -------- --------- -------- 12345 Cupertino CA 83472 Redmond WA 83492 Boston MA
Следующий фрагмент кода демонстрирует выполнение SQL-запроса, который возвращает
коллекцию строк, в которой колонка 1 - это
int, колонка 2 -
String и колонка 3 - массив байтов:
java.sql.Statement stmt = conn.createStatement(); ResultSet r = stmt.executeQuery("SELECT a, b, c FROM Table1"); while (r.next()) { // Напечатать значения в текущей строке. int i = r.getInt("a"); String s = r.getString("b"); float f = r.getFloat("c"); System.out.println("ROW = " + i + " " + s + " " + f); }
ResultSet содержит т.н. курсор, который указывает на текущую строку
данных. Каждый раз, когда выполняется метод
next, курсор перемещается на одну строку вниз.
Изначально курсор спозиционирован перед первой строкой, и первый вызов
next премещает его на первую строку (она становится текущей).
С каждым успешным вызовом next курсор перемещается вниз на одну строку, начиная
с самой верхней в ResultSet.
Курсор сохраняется до тех пор, пока не закроется объект ResultSet
или его родительский объект Statement.
В SQL курсор для результирующей таблицы имеет имя. Если БД поддерживает
позиционированные обновления или позиционированные удаления, то командам обновления
или удаления можно передать в качестве параметра имя курсора. Это имя
может быть получено с помощью
вызова getCursorName.
Заметим, что не все СУБД поддерживают позиционированные обновления или удаления.
Чтобы узнать, поддерживает ли данное соединение эти операции или нет, можно
вызвать методы DatabaseMetaData.supportsPositionedDelete и supportsPositionedUpdate.
getXXX предоставляют доступ к значениям в колонках в текущей строке.
В пределах одной строки значения могут быть считаны в любом порядке, но
ради обеспечения большей совместимости рекомендуется считывать их подряд
слева направо и делать это только один раз.
Для указания колонки можно использовать либо ее имя, либо ее номер.
Например, если вторая колонка объекта
ResultSet rs называется "title" и хранит
строковое значение, то извлечь его можно одним из двух способов:
String s = rs.getString("title"); String s = rs.getString(2);Имейте ввиду, что колонки нумеруются слева направо, начиная с 1. Имена колонок в вызове методов
getXXX нечувствительны к регистру букв.
Вариант с использование имен колонок существует для того, чтобы пользователь
задавал методам getXXX те же имена колонок, что он использует в запросе.
Если выражение select не указывает имена колонок
(например "select * from table1" или в случаях, когда колонка вычисляется)
должны использоваться номера колонок. В этих случаях пользователь не может
знать наверняка имена колонок.
В нектороых случаях имена двух колонок могут совпадать. Тогда при использовании
имен колонок в методах getXXX возвращается значение первой подходящей колонки.
Таким образом, чтобы считать значение других колонок с таким же именем,
надо использовать индексы колонок. Кроме того, использование индексов немного
эффективнее.
Информацию о колонках в ResultSet можно получить с помощтю
вызова
ResultSet.getMetaData. Возвращаемый объект ResultSetMetaData
содержит информацию о количестве, типах и свойствах колонок объекта
ResultSet.
Если известно имя колонки, но не ее индекс, то для поиска номера колонки
можно использовать
метод findColumn.
getXXX пытаются сконвертировать низкоуровневые данные
в типы данных языка Java. Например, метод
если метод getXXX - это getString и тип данных в БД -
VARCHAR, драйвер JDBC сконвертирует
VARCHAR в объект String. Возвращаемым
из метода getString значением будет Java-объект String.
Следующая таблица показывает, какие типы данных различные методы
getXXX могут считывать и какие JDBC-типы (SQL-типы) рекомендуются
для этих методов. Знак x означает, что метод getXXX
подходит к соответствующему типу данных;
знак X означает рекомендуемый метод getXXX
для данного типа.
Например, значение LONGVARCHAR можно извлечь любым из методов
getXXX кроме getBytes и getBinaryStream,
но рекомендуется использовать методы getAsciiStream
и getUnicodeStream. Метод getObject возвращает любой тип
данных как Object и используется в тех случаях, когда соответствующий
низкоуровневый тип данных является специфичным для данной СУБД или когда приложению
необходимо принять любой тип данных.
Использование методов ResultSet.getXXX при доступе к различным типам данных SQL.
"x" означает, что метод getXXX может быть использован,
"X" означает, что соответствующий метод рекомендуется использовать для этого типа данных.
| T I N Y I N T | S M A L L I N T | I N T E G E R | B I G N T | R E A L | F L O A T | D O U B L E | D E C I M A L | N U M E R I C | B I T | C H A R | V A R C H A R | L O N G V A R C H A R | B I N A R Y | V A R B I N A R Y | L O N G V A R B I N A R Y | D A T E | T I M E | T I M E S T A M P | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| getByte | X | x | x | x | x | x | x | x | x | x | x | x | x | ||||||
| getShort | x | X | x | x | x | x | x | x | x | x | x | x | x | ||||||
| getInt | x | x | X | x | x | x | x | x | x | x | x | x | x | ||||||
| getLong | x | x | x | X | x | x | x | x | x | x | x | x | x | ||||||
| getFloat | x | x | x | x | X | x | x | x | x | x | x | x | x | ||||||
| getDouble | x | x | x | x | x | X | X | x | x | x | x | x | x | ||||||
| getBigDecimal | x | x | x | x | x | x | x | X | X | x | x | x | x | ||||||
| getBoolean | x | x | x | x | x | x | x | x | x | X | x | x | x | ||||||
| getString | x | x | x | x | x | x | x | x | x | x | X | X | x | x | x | x | x | x | x |
| getBytes | X | X | x | ||||||||||||||||
| getDate | x | x | x | X | x | ||||||||||||||
| getTime | x | x | x | X | x | ||||||||||||||
| getTimestamp | x | x | x | x | X | ||||||||||||||
| getAsciiStream | x | x | X | x | x | x | |||||||||||||
| getUnicodeStream | x | x | X | x | x | x | |||||||||||||
| getBinaryStream | x | x | X | ||||||||||||||||
| getObject | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x |
ResultSet возможно получать очень большие данные типа
LONGVARBINARY или LONGVARCHAR. Методы
getBytes и getString возвращают эти данные в виде одного
большого куска (вплоть до пределов, которые можно узнать с помощью метода
Statement.getMaxFieldSize). Тем не менее, может оказаться удобнее
считывать очень большие данные небольшими кусками. Это делается с помощью потоков
(java.io.InputStream), которые возвращаются некоторыми методами
ResultSet. Обратите внимание на то, что к этим потокам
надо обращаться сразу, так как они будут закрыты при следующем вызове
getXXX объекта ResultSet.
(Такое поведение диктуется низкоуровневой реализацией доступа к
большим двоичным объектам)
В JDBC API есть три отдельных метода для получения потоков:
getBinaryStream возвращает поток байтов "как есть", без какого-либо
предварительного преобразования
getAsciiStream возвращает поток, состоящий из однобайтовых
ASCII-символов.
getUnicodeStream возвращает поток двухбайтных символов
Unicode.
Следующий пример демонстрирует использование getAsciiStream:
java.sql.Statement stmt = con.createStatement(); ResultSet r = stmt.executeQuery("SELECT x FROM Table2"); // Теперь считываем колонку 1 результатов кусками по 4 K: byte buff = new byte[4096]; while (r.next()) { Java.io.InputStream fin = r.getAsciiStream(1); for (;;) { int size = fin.read(buff); if (size == -1) { // в конце потока break; } // Отослать заполненный буфер в ASCII-поток: output.write(buff, 0, size); } }
ResultSet.wasNull для выяснения этого факта. Значение true означает,
что считанное значение равно NULL.
Значение же, возвращаемое в этом случае методом
ResultSet.getXXX, равно:
null для тех из методов getXXX, которые возвращают объекты
(такие методы, как getString, getBigDecimal, getBytes, getDate, getTime, getTimestamp, getAsciiStream, getUnicodeStream, getBinaryStream, getObject).
getByte, getShort, getInt, getLong, getFloat, and getDouble.
false в случае getBoolean.
executeQuery (который
возвращает единственный ResultSet), либо executeUpdate
(который может использоваться для любых запросов на изменение БД и которые возвращают
количество измененных строк). Тем не менее, в некоторых случаях приложению
заведомо неизвестно, возвратит ли данный запрос результат или нет.
Кроме того, некоторые хранимые процедры могут возвратить несколько наборов данных
и/или счетчиков обновления.
На этот случай в JDBC есть механизм, когда приложение может обрабатывать произвольную
коллекцию наборов результатов или счетчиков обновления. Этот механизм
основан на вызове метода
execute и последующем вызове трех других методов
getResultSet, getUpdateCount и
getMoreResults. Эти методы позволяют приложению получать результаты
запроса поочереди и для каждого результата определять, является ли он набором
данных или счетчиком обновлений.
Нет никакой необходимости закрывать ResultSet; это делается автоматически
родительским объектом Statement, когда последний закрывается,
выполняется повторно или используется для извлечения следующего результата
в последовательности нескольких результатов.