На прошлой неделе Даниэль Рубио представил обзор API JDBC. В этой серии статей о JDBC FAQ на этой неделе мы рассмотрим объект JDBC ResultSet и предоставим обзор некоторых ключевых методов, которые его составляют.
Прочитайте другие части в серии часто задаваемых вопросов JDBC DZone :
Что такое ResultSet?
ResultSet — это табличная структура, содержащая набор данных, возвращаемый при выполнении оператора запроса. Структура содержит как сами данные, так и большое количество метаданных, описывающих содержащие данные. Метаданные включают типы столбцов, имена столбцов, а также другую информацию.
Объект ResultSet по умолчанию доступен только для чтения и только для пересылки, что означает, что мы можем выполнять итерацию только от начала ResultSet до его конца, а не наоборот. Другая функция по умолчанию указывает, что мы можем только читать данные из ResultSet и не обновлять, вставлять или удалять данные, когда ResultSet создается с использованием параметров построения по умолчанию.
Объект ResultSet предоставляет необходимые методы для:
- перебирать содержащиеся строки как вперед, так и назад
- читать или обновлять содержимое каждого столбца
- вставьте новые строки в ResultSet и, наконец, в базовую таблицу
- удалить строки из ResultSet и лежащей в основе таблицы.
- Прочитайте метаданные, связанные с ResultSet
- переходить между рядами, предоставляя абсолютный номер строки или относительную разницу.
Как получить имена столбцов для строк, возвращаемых в ResultSet?
Мы можем использовать метаданные ResultSet для получения имен столбцов. Например, предполагая, что у нас есть ResultSet, который мы создали в первом вопросе, мы можем использовать следующий фрагмент, чтобы получить имя столбца для первого столбца в ResultSet.
ResultSetMetaData rsmd = rs.getMetaData(); String value = rsmd.getColumnLabel(1);
Мы можем использовать метод rsmd.getColumnCount (), чтобы получить количество столбцов, а затем использовать цикл, чтобы получить все имена столбцов и использовать их для создания модели данных JTable или чего угодно.
Как получить всю строку данных одновременно, вместо вызова отдельного метода ResultSet.getX.XX для каждого столбца?
При использовании JDBC невозможно получить целую строку ResulSet за один вызов. Единственный способ извлечь данные строки из результирующего набора — это с помощью методов-получателей получить значение каждого столбца текущей строки.
В API JDBC есть метод getColumnCount. Есть ли подобный метод, чтобы найти количество строк в ResultSet?
Невозможно найти количество строк в ResultSet, и даже если такой метод присутствует, результат будет неточным, поскольку методы setFetchSize и setMaxRows будут влиять на количество строк, присутствующих в ResultSet.
Лучший способ получить количество строк для определенного оператора — выполнить другой запрос, применив функцию count к основному запросу.
Что делает setFetchSize ()?
Мы можем использовать метод SetFetchSize, чтобы изменить количество блоков данных или строк, которые должны быть переданы клиенту с сервера после выполнения оператора. Этот метод может действовать по-разному на разных драйверах разных поставщиков. Значение по умолчанию SetFetchSize зависит от поставщика и требует, чтобы вы обратились к документации поставщика, чтобы узнать, каково его поведение по умолчанию.
И ResultSet, и Statement имеют метод SetFetchSize. При использовании в операторе все ResultSets, возвращаемые этим оператором, будут иметь одинаковый размер выборки.
В чем разница между setMaxRows (int) и SetFetchSize (int)? Можно ли сократить время обработки?
Метод setMaxRows ResultSet указывает, сколько строк ResultSet может содержать одновременно. Любое количество строк больше указанного будет удалено и не будет загружено в ResultSet.
Различные поставщики используют разные стратегии для реализации этих методов. По умолчанию для setMaxRows установлено значение 0, что означает, что все строки будут включены в ResultSet.
Таким образом, различия заключаются в том, что влияет на вызов метода: setMaxRows влияет на объект JDBC на стороне клиента, а setFetchSize влияет на то, как база данных возвращает данные ResultSet.
Как я могу обновить ResultSet программно?
Когда мы говорим об обновлении, мы можем просто подразумевать обновление записи, вставку записи или удаление записи из ResultSet, а затем принятие изменения в базовой таблице. Прежде чем перейти к примеру кода, мы должны знать, что все условия, применяемые для создания обновляемого ResultSet, применимы и здесь.
Чтобы обновить запись в ResultSet, нам нужно навести курсор на запись и затем использовать методы setXXX для обновления столбцов. Например:
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("SELECT name ,lastName ,sn FROM table_1");
rs.absolute(5); //moving the cursor to the first row
rs.updateString("name", “john”); // update the name field of the current row
rs.updateRow(); //persist the change
Мы можем перебрать ResultSet и обновить записи или просто восстановить обновления из изменения JTable.
Чтобы удалить запись, нам просто нужно переместить курсор на запись, которую мы хотим удалить, и вызвать метод deleteRow. Например:
rset.absolute(5); rset.deleteRow();
Чтобы вставить строку, мы можем использовать следующую процедуру, чтобы вставить строку в ResultSet и ожидать, что она повлияет на базовую таблицу.
rset.moveToInsertRow(); // prepare a new row
Затем вы можете использовать методы updateXXX, чтобы установить значение каждого столбца в ResultSet, например:
rset.updateString(1, "John"); rset.updateString(2, "Doe"); rset.updateString(3, "sn15308798");
Наконец, вы можете вызвать метод insertRow, чтобы сделать изменения постоянными:
rset.insertRow();
Как мне создать обновляемый ResultSet?
Обновляемый ResultSet позволяет нам обновлять ResultSet программно. Хотя почти все драйверы поддерживают обновляемый ResultSet, для поставщиков драйверов JDBC это дополнительная функция для реализации этой возможности. Чтобы получить обновляемый ResultSet, вам нужно установить тип параллелизма ResultSet равным ResultSet.CONCUR_UPDATABLE при его создании. Например, следующий фрагмент показывает, как мы можем его создать.
try {
Statement stmt = connection.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("SELECT name ,lastName ,sn FROM table_1");
}
catch (SQLException e) {
}
Если драйвер не поддерживает обновляемый ResultSet, он возвратит обычный ResultSet только для чтения.
К обновляемому ResultSet применяются некоторые условия, которые включают:
- Оператор SELECT должен иметь одну базовую таблицу; никакие объединения и никакие функции агрегирования не допускаются. Это похоже на выбор для условия обновления в простом SQL.
- PK базовой таблицы должен присутствовать в ResultSet, чтобы он мог распространять изменения на правильную строку в таблице.
Обратите внимание, что создание обновляемого ResultSet имеет свои накладные расходы, и мы должны создавать его только тогда, когда нам это нужно. Передача без параметра при создании ResultSet означает, что мы хотим ResultSet только для чтения.
Если вам интересно узнать некоторые из других типов ResultSets и значение каждого из параметров метода CreateStatement, то следующий раздел для вас:
Первый аргумент в CreateStatement указывает тип объекта ResultSet:
- TYPE_FORWARD_ONLY: ResultSet только позволит курсору двигаться вперед.
- TYPE_ SCROLL_INSENSITIVE: ResultSet этого типа не отражает изменения, которые были внесены в него, пока он открыт.
- TYPE_SCROLL_SENSITIVE: Любые изменения, внесенные в ResultSet, пока он открыт, будут отражены в самом ResultSet.
Второй аргумент в CreateStatement указывает, является ли ResultSet обновляемым или нет. Для этого параметра допустимы следующие значения:
- CONCUR_READ_ONLY: ResultSet этого типа доступен только для чтения
- CONCUR_UPDATABLE: Мы можем обновить созданный набор результатов с этим значением для упомянутого параметра.
Как я могу переместить курсор в прокручиваемый ResultSet?
ResultSet, созданный без передачи параметра прокрутки, будет ResultSet только для пересылки, что означает, что мы не можем перемещаться назад в списке или строках внутри ResultSet.
Следующий фрагмент создает прокручиваемый обновляемый ResultSet.
try {
Statement stmt = connection.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("SELECT name, lastName, sn FROM table_1");
}
catch (SQLException e) {
}
Мы можем выполнить итерацию вперед в этом ResultSet, используя следующий фрагмент:
while (rs.next()) {
String name = rs.getString("name");
String lastName = rs.getString ("lastName");
String sn = rs.getString(“sn”);
System.out.println(name + " " + lastName + “ ” +sn);
}
Для повторения в обратном направлении мы можем использовать следующий фрагмент:
while (rs.previous()) {
String name = rs.getString("name");
String lastName = rs.getString ("lastName");
String sn = rs.getString(“sn”);
System.out.println(name + " " + lastName + “ ” +sn);
}
Этот фрагмент работает при условии, что мы находимся в конце ResultSet, и мы хотим вернуться к первой строке. В следующей таблице приведен список методов, которые помогают нам в дальнейшем использовать прокручиваемость:
Like updatability, the scrollability of a ResultSet imposes some overhead. If you don’t need to move backward in the ResultSet it is probably better to use the forward-only ResultSet.
Why can’t I invoke the ResultSet methods afterLast and beforeFirst when the method next works?
The most probable case is that you are using a driver which does not support a scrollable ResultSet or the ResultSet is not created as a forward only ResultSet .