Интерфейс Java JDBC ResultSet представляет результат запроса к базе данных. Текст о запросах показывает, как результат запроса возвращается как java.sql.ResultSet. Затем этот ResultSet повторяется для проверки результата.
ResultSet содержит записи
JDBC ResultSet содержит записи. Каждая запись содержит набор столбцов. Каждая запись содержит одинаковое количество столбцов, хотя не все столбцы могут иметь значение. Столбец может иметь нулевое значение. Вот иллюстрация JDBC ResultSet:

Этот ResultSet имеет 3 разных столбца(имя, возраст, пол) и 3 записи с разными значениями для каждого столбца.
Создание ResultSet
Вы создаете ResultSet, выполняя Statement или PreparedStatement, например так:
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery("select * from people");
Или вот так:
String sql = "select * from people"; PreparedStatement statement = connection.prepareStatement(sql); ResultSet result = statement.executeQuery();
Тип ResultSet, параллелизм и удерживаемость
Когда вы создаете ResultSet, вы можете установить три атрибута. Эти:
- Тип
- совпадение
- Holdability
Вы устанавливаете их уже при создании Statement или PreparedStatement, например так:
Statement statement = connection.createStatement(
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY,
ResultSet.CLOSE_CURSORS_OVER_COMMIT
);
PreparedStatement statement = connection.prepareStatement(sql,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY,
ResultSet.CLOSE_CURSORS_OVER_COMMIT
);
Что именно означают эти атрибуты, объясняется далее в этом тексте. Но теперь вы сейчас, где их указать.
Итерация
Для итерации ResultSet вы используете его метод next(). Метод next() возвращает значение true, если ResultSet имеет следующую запись, и перемещает ResultSet, чтобы он указывал на следующую запись. Если больше не было записей, next() возвращает false, и вы больше не можете. Как только метод next() вернул false, вы не должны больше его вызывать. Это может привести к исключению.
Вот пример итерации ResultSet с использованием метода next():
while(result.next()) {
// ... get column values from this record
}
Как видите, метод next() на самом деле вызывается до доступа к первой записи. Это означает, что ResultSet начинает указывать перед первой записью. После того, как next() был вызван один раз, он указывает на первую запись.
Точно так же, когда next() вызывается и возвращает false, ResultSet фактически указывает после последней записи.
Вы не можете получить количество строк в ResultSet, за исключением случаев, когда вы выполняете все итерации по нему и подсчитываете строки. Однако, если ResultSet предназначен только для пересылки, вы не сможете впоследствии перемещаться назад. Даже если бы вы могли двигаться назад, это был бы медленный способ подсчета строк в ResultSet. Вам лучше структурировать свой код так, что вам не нужно заранее знать количество записей.
Доступ к значениям столбца
При переборе ResultSet вы хотите получить доступ к значениям столбцов каждой записи. Вы делаете это, вызывая один или несколько методов getXXX(). Вы передаете имя столбца, чтобы получить значение многих методов getXXX(). Например:
while(result.next()) {
result.getString ("name");
result.getInt ("age");
result.getBigDecimal("coefficient");
// etc.
}
Есть много методов getXXX(), которые вы можете вызвать, которые возвращают значение столбца в виде определенного типа данных, например String, int, long, double, BigDecimal и т. Д. Все они берут имя столбца, чтобы получить столбец значение для, как параметр. Вот список быстрых примеров этих методов getXXX():
result.getArray("columnName");
result.getAsciiStream("columnName");
result.getBigDecimal("columnName");
result.getBinaryStream("columnName");
result.getBlob("columnName");
result.getBoolean("columnName");
result.getBlob("columnName");
result.getBoolean("columnName");
result.getByte("columnName");
result.getBytes("columnName");
result.getCharacterStream("columnName");
result.getClob("columnName");
result.getDate("columnName");
result.getDouble("columnName");
result.getFloat("columnName");
result.getInt("columnName");
result.getLong("columnName");
result.getNCharacterStream("columnName");
result.getObject("columnName");
result.getRef("columnName");
result.getRowId("columnName");
result.getShort("columnName");
result.getSQLXML("columnName");
result.getString("columnName");
result.getTime("columnName");
result.getTimestamp("columnName");
result.getUnicodeStream("columnName");
result.getURL("columnName");
Методы getXXX() также существуют в версиях, которые принимают индекс столбца вместо имени столбца. Например:
while(result.next()) {
result.getString (1);
result.getInt (2);
result.getBigDecimal(3);
// etc.
}
Индекс столбца обычно зависит от индекса столбца в операторе SQL. Например, оператор SQL
select name, age, coefficient from person
имеет три столбца. Имя столбца указывается первым и, следовательно, будет иметь индекс 1 в ResultSet. Возраст столбца будет иметь индекс 2, а коэффициент столбца будет иметь индекс 3.
Иногда вы не знаете индекс определенного столбца раньше времени. Например, если вы используете SQL-запрос select * from, вы не знаете последовательность столбцов.
Если вы не знаете индекс определенного столбца, вы можете найти индекс этого столбца, используя метод ResultSet.findColumn(String columnName), например:
int nameIndex = result.findColumn("name");
int ageIndex = result.findColumn("age");
int coeffIndex = result.findColumn("coefficient");
while(result.next()) {
String name = result.getString (nameIndex);
int age = result.getInt (ageIndex);
BigDecimal coefficient = result.getBigDecimal(coeffIndex);
}
ResultSet Types
ResultSet может быть определенного типа. Тип определяет некоторые характеристики и возможности ResultSet.
Не все типы поддерживаются всеми базами данных и драйверами JDBC. Вам придется проверить свою базу данных и драйвер JDBC, чтобы увидеть, поддерживает ли он тип, который вы хотите использовать. Метод DatabaseMetaData.supportsResultSetType(int type) возвращает true или false в зависимости от того, поддерживается данный тип или нет. Класс DatabaseMetaData описан в следующем тексте.
На момент написания статьи существует три типа ResultSet:
- ResultSet.TYPE_FORWARD_ONLY
- ResultSet.TYPE_SCROLL_INSENSITIVE
- ResultSet.TYPE_SCROLL_SENSITIVE
Тип по умолчанию — TYPE_FORWARD_ONLY
TYPE_FORWARD_ONLY означает, что ResultSet можно перемещать только вперед. То есть вы можете перемещаться только из строки 1, строки 2, строки 3 и т. Д. В ResultSet вы не можете двигаться назад.
TYPE_SCROLL_INSENSITIVE означает, что ResultSet можно перемещать(прокручивать) как вперед, так и назад. Вы также можете перейти к позиции относительно текущей позиции или перейти к абсолютной позиции. ResultSet нечувствителен к изменениям в базовом источнике данных, пока ResultSet открыт. То есть, если запись в ResultSet изменяется в базе данных другим потоком или процессом, она не будет отражена в уже открытых ResulsSet этого типа.
TYPE_SCROLL_SENSITIVE означает, что ResultSet можно перемещать(прокручивать) как вперед, так и назад. Вы также можете перейти к позиции относительно текущей позиции или перейти к абсолютной позиции. ResultSet чувствителен к изменениям в базовом источнике данных, пока ResultSet открыт. То есть, если запись в ResultSet изменяется в базе данных другим потоком или процессом, она будет отражена в уже открытых ResulsSet этого типа.
Методы навигации
Интерфейс ResultSet содержит следующие методы навигации. Помните, что не все методы работают со всеми типами ResultSet. Какие методы работают, зависит от вашей базы данных, драйвера JDBC и типа ResultSet.
Интерфейс ResultSet также содержит набор методов, которые вы можете использовать для запроса текущей позиции ResultSet. Эти:
Наконец, интерфейс ResultSet также содержит метод для обновления строки изменениями базы данных, если ResultSet чувствителен к изменениям.
Concurrency
Параллельность ResultSet определяет, может ли ResultSet обновляться или только считываться.
Некоторые базы данных и драйверы JDBC поддерживают обновление ResultSet, но не все базы данных и драйверы JDBC поддерживают это. Метод DatabaseMetaData.supportsResultSetConcurrency(int concurrency) возвращает значение true или false в зависимости от того, поддерживается данный режим параллелизма или нет. Класс DatabaseMetaData описан в следующем тексте.
ResultSet может иметь один из двух уровней параллелизма:
- ResultSet.CONCUR_READ_ONLY
- ResultSet.CONCUR_UPDATABLE
CONCUR_READ_ONLY означает, что ResultSet может быть прочитан только.
CONCUR_UPDATABLE означает, что ResultSet может быть прочитан и обновлен.
Обновление ResultSet
Если ResultSet является обновляемым, вы можете обновить столбцы каждой строки в ResultSet. Вы делаете это, используя множество методов updateXXX(). Например:
result.updateString ("name" , "Alex");
result.updateInt ("age" , 55);
result.updateBigDecimal("coefficient", new BigDecimal("0.1323");
result.updateRow();
Вы также можете обновить столбец, используя индекс столбца вместо имени столбца. Вот пример:
result.updateString (1, "Alex");
result.updateInt (2, 55);
result.updateBigDecimal(3, new BigDecimal("0.1323");
result.updateRow();
Обратите внимание на вызов updateRow(). Когда вызывается updateRow(), база данных обновляется со значениями строки. Если вы не вызываете этот метод, значения, обновленные в ResultSet, никогда не отправляются в базу данных. Если вы вызываете updateRow() внутри транзакции, данные фактически не фиксируются в базе данных, пока транзакция не будет зафиксирована.
Вставка строк в ResultSet
Если ResultSet является обновляемым, в него также можно вставлять строки. Вы делаете это:
- вызов ResultSet.moveToInsertRow()
- обновить значения столбца строки
- вызвать ResultSet.insertRow()
Вот пример:
result.moveToInsertRow();
result.updateString (1, "Alex");
result.updateInt (2, 55);
result.updateBigDecimal(3, new BigDecimal("0.1323");
result.insertRow();
result.beforeFirst();
Строка, на которую указывает после вызова moveToInsertRow(), является специальной строкой, буфером, который можно использовать для построения строки, пока все значения столбцов не будут установлены в строке правильно.
Когда строка будет готова для вставки в ResultSet, вызовите метод insertRow().
После вставки строки ResultSet по-прежнему указывает на строку вставки. Однако вы не можете быть уверены, что произойдет, если вы попытаетесь получить к нему доступ после вставки строки. Поэтому вы должны переместить ResultSet в правильную позицию после вставки новой строки. Если вам нужно вставить другую строку, явно вызовите moveToInsertRow(), чтобы сообщить об этом ResultSet.
Удерживаемость ResultSet
Удерживаемость ResultSet определяет, будет ли ResultSet закрыт при вызове метода commit() базового соединения.
Не все режимы удержания поддерживаются всеми базами данных и драйверами JDBC. DatabaseMetaData.supportsResultSetHoldability(int holdability) возвращает true или false в зависимости от того, поддерживается данный режим удержания или нет. Класс DatabaseMetaData описан в следующем тексте.
Существует два типа удержания:
- ResultSet.CLOSE_CURSORS_OVER_COMMIT
- ResultSet.HOLD_CURSORS_OVER_COMMIT
Удерживаемость CLOSE_CURSORS_OVER_COMMIT означает, что все экземпляры ResultSet закрываются при вызове метода connection.commit() для соединения, создавшего ResultSet.
Удерживаемость HOLD_CURSORS_OVER_COMMIT означает, что ResultSet остается открытым при вызове метода connection.commit() для соединения, создавшего ResultSet.
Удерживаемость HOLD_CURSORS_OVER_COMMIT может быть полезна, если вы используете ResultSet для обновления значений в базе данных. Таким образом, вы можете открыть ResultSet, обновить в нем строки, вызвать connection.commit() и при этом оставить тот же ResultSet открытым для будущих транзакций в тех же строках.
