Получаем данные из ResultSet
Первую программу мы написали и она отлично отработала. Мы написали запрос, выполнили его, и в результате метод executeQuery() вернул нам объект ResultSet , который содержит все результаты запроса. И теперь мы попробуем разобраться, как эти результаты из него получить.
Результат запроса может содержать тысячи строк и сотни колонок различных типов, так что эта не такая тривиальная задача, как тебе кажется. Например, в базе могут храниться картинки, тогда ты можешь получить картинку в виде набора байт или же InputStream для ее загрузки.
Но начнем мы с самого простого — с понятия “текущей строки результата”. Так как строк у результата обычно очень много, то объект ResultSet имеет у себя внутри указатель на текущую строку. И последовательно переключает строки для их чтения с помощью метода next() .
Такой подход в первую очередь сделан для оптимизации. JDBC Driver может не загружать строки из базы, пока ты последовательно не дойдешь до их чтения. FileInputStream ты тоже читаешь последовательно с начала и до конца. Так что такой подход должен быть тебе знаком и понятен.
Однако же, если тебе очень нужно, то файлы можно читать в любом месте с помощью класса RandomAccessFile .
Класс ResultSet тоже позволяет что-то подобное и позволяет двигать текущую строку по результату куда угодно. Для этого у него есть такие методы:
Метод | Описание | ||
---|---|---|---|
1 | next() | Переключиться на следующую строку | |
2 | previous() | Переключиться на предыдущую строку | |
3 | isFirst() | Текущая строка первая? | |
4 | isBeforeFirst() | Мы перед первой строкой? | |
5 | isLast() | Текущая строка последняя? | |
6 | isAfterLast() | Мы после последней сроки? | |
7 | absolute(int n) | Делает N-ю строку текущей | |
8 | relative(int n) | Двигает текущую строку на N позиций вперед. N может быть getRow() | Возвращает номер строки |
Методы достаточно простые, однако нужно сделать два пояснения. Результаты как бы обрамлены пустыми строками с обоих сторон. Поэтому изначально текущая строка находится перед первой строкой результата. И чтобы получить первую строку, нужно хотя бы раз вызвать метод next() .
Если ты на последней стоке вызвал метод next() , то ты перешел на строку после последней. Данных из нее прочитать ты не можешь, но никакой ошибки не произойдет. Тут метод isAfterLast() будет возвещать true в качестве результата.
Statement statement = connection.createStatement(); ResultSet results = statement.executeQuery("SELECT * FROM user"); System.out.println( results.getRow() ); // 0 System.out.println( results.isBeforeFirst() ); // true System.out.println( results.isFirst() ); // false results.next(); System.out.println( results.getRow() ); // 1 System.out.println( results.isBeforeFirst() ); // false System.out.println( results.isFirst() ); // true results.next(); System.out.println( results.getRow() ); // 2 System.out.println( results.isBeforeFirst() ); // false System.out.println( results.isFirst() ); // false
Получение данных из текущей строки
Ты научился виртуозно управлять текущей строкой. Теперь давай разберем, как из нее получать данные. Для этого у объекта ResultSet есть специальные методы, которые все можно описать одним шаблоном:
Впрочем, если у колонки есть имя, то можно получать и по имени колонки:
Ниже я приведу таблицу, которая тебе поможет связать типы данных SQL и методы ResultSet:
SQL Datatype | getXXX() Methods |
---|---|
CHAR | getString() |
VARCHAR | getString() |
INT | getInt() |
FLOAT | getDouble() |
CLOB | getClob() |
BLOB | getBlob() |
DATE | getDate() |
TIME | getTime() |
TIMESTAMP | getTimestamp() |
Получение разных данных о ResultSet
Как читать данные из текущей строки мы разобрались: и по номеру колонки, и по ее имени. Кстати, а как узнать имя колонки по ее номеру? Или количество колонок в результате?
С одной стороны, если ты пишешь запрос, то ты вроде бы должен все это знать. С другой стороны, мы можем писать программу, которая отображает результат запроса на экран: запрос нам передают и мы хотим просто отобразить на экране (в консоли, веб-странице) все, что нам вернул SQL-сервер.
Для этого у JDBC есть специальный объект – интерфейс ResultSetMetaData . Получить объект этого типа достаточно просто:
Statement statement = connection.createStatement(); ResultSet results = statement.executeQuery("SELECT * FROM user"); ResultSetMetaData resultSetMetaData = results.getMetaData();
У интерфейса ResultSetMetaData есть очень интересные методы. Ниже приведу самые популярные из них:
1 | getColumnCount() | Возвращает количество колонок результата |
2 | getColumnName(int column) | Возвращает имя колонки |
3 | getColumnLabel(int column) | Возвращает description колонки |
4 | getColumnType() | Возвращает тип колонки: число (специальный код) |
5 | getColumnTypeName() | Возвращает тип колонки: строка |
6 | getColumnClassName() | Возвращает имя java-класса для типа колонки |
7 | getTableName() | Возвращает имя таблицы |
8 | getCatalogName() | Возвращает имя каталога колонки |
9 | getSchemaName() | Возвращает имя схемы базы данных |
10 | isAutoIncrement(int column) | Колонка поддерживает AUTO INCREMENT? |
11 | isNullable() | Колонка может содержать NULL? |
Давай с его помощью немного узнаем о нашей таблице:
ResultSetMetaData metaData = results.getMetaData(); int columnCount = metaData.getColumnCount(); for (int column = 1; column
Важно! Обрати внимание, что колонки нумеруются с 1. Строки, кстати, тоже. Как это необычно, да?
И вот какой результат я получил после запуска программы:
«C:\Program Files\Java\jdk-17.0.3.1\bin\java.exe… | |||
id | java.lang.Integer | INT | 4 |
name | java.lang.String | VARCHAR | 12 |
level | java.lang.Integer | INT | 4 |
created_date | java.sql.Date | DATE | 91 |
Process finished with exit code 0 |