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
, когда последний закрывается,
выполняется повторно или используется для извлечения следующего результата
в последовательности нескольких результатов.