След: JDBC (ТМ) Доступ к базе данных
Урок: Основы JDBC
Получение и Изменение Значений от Наборов результатов
Домашняя страница > JDBC (ТМ) Доступ к базе данных > Основы JDBC

Получение и Изменение Значений от Наборов результатов

Следующий метод, CoffeesTable.viewTable выводит содержание COFFEES таблицы, и демонстрируют использование ResultSet объекты и курсоры:

public static void viewTable(Connection con, String dbName)
    throws SQLException {

    Statement stmt = null;
    String query =
        "select COF_NAME, SUP_ID, PRICE, " +
        "SALES, TOTAL " +
        "from " + dbName + ".COFFEES";

    try {
        stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery(query);
        while (rs.next()) {
            String coffeeName = rs.getString("COF_NAME");
            int supplierID = rs.getInt("SUP_ID");
            float price = rs.getFloat("PRICE");
            int sales = rs.getInt("SALES");
            int total = rs.getInt("TOTAL");
            System.out.println(coffeeName + "\t" + supplierID +
                               "\t" + price + "\t" + sales +
                               "\t" + total);
        }
    } catch (SQLException e ) {
        JDBCTutorialUtilities.printSQLException(e);
    } finally {
        if (stmt != null) { stmt.close(); }
    }
}

A ResultSet объект является таблицей данных, представляющих набор результатов базы данных, который обычно сгенерирован, выполняя оператор, который запрашивает базу данных. Например, CoffeeTables.viewTable метод создает a ResultSet, rs, когда это выполняет запрос через Statement объект, stmt. Отметьте это a ResultSet объект может быть создан через любой объект, который реализует Statement интерфейс, включая PreparedStatement, CallableStatement, и RowSet.

Вы получаете доступ к данным в a ResultSet объект через курсор. Отметьте, что этот курсор не является курсором базы данных. Этот курсор является указателем, который указывает на одну строку данных в ResultSet. Первоначально, курсор располагается перед первой строкой. Метод ResultSet.next перемещает курсор в следующую строку. Этот метод возвраты false если курсор располагается после последней строки. Этот метод неоднократно вызывает ResultSet.next метод с a while цикл, чтобы выполнить итерации через все данные в ResultSet.

Эта страница затрагивает следующие темы:

Интерфейс ResultSet

ResultSet интерфейс обеспечивает методы для получения и управления результатами выполняемых запросов, и ResultSet у объектов могут быть различная функциональность и характеристики. Эти характеристики являются типом, параллелизмом, и курсором holdability.

Типы ResultSet

Тип a ResultSet объект определяет уровень своей функциональности в двух областях: пути, которыми курсором можно управлять, и как параллельные изменения, произведенные в базовом источнике данных, отражаются ResultSet объект.

Чувствительность a ResultSet объект определяется одним из три отличающийся ResultSet типы:

Значение по умолчанию ResultSet тип TYPE_FORWARD_ONLY.

Отметьте: Не все базы данных и драйверы JDBC поддерживают все ResultSet типы. Метод DatabaseMetaData.supportsResultSetType возвраты true если указанное ResultSet тип поддерживается и false иначе.

Параллелизм ResultSet

Параллелизм a ResultSet объект определяет, какой уровень функциональности обновления поддерживается.

Есть два уровня параллелизма:

Значение по умолчанию ResultSet параллелизм CONCUR_READ_ONLY.

Отметьте: Не все драйверы JDBC и базы данных поддерживают параллелизм. Метод DatabaseMetaData.supportsResultSetConcurrency возвраты true если указанный уровень параллелизма поддерживается драйвером и false иначе.

Метод CoffeesTable.modifyPrices демонстрирует, как использовать a ResultSet возразите, чей уровень параллелизма CONCUR_UPDATABLE.

Курсор Holdability

Вызов метода Connection.commit может закрыться ResultSet объекты, которые были созданы во время текущей транзакции. В некоторых случаях, однако, это, возможно, не требуемое поведение. ResultSet свойство holdability передает управлению приложением ли ResultSet объекты (курсоры) закрываются, когда фиксацию вызывают.

Следующий ResultSet константы могут быть предоставлены Connection методы createStatement, prepareStatement, и prepareCall:

Курсор значения по умолчанию holdability изменяется в зависимости от Вашего DBMS.

Отметьте: Не все драйверы JDBC и базы данных поддерживают holdable и non-holdable курсоры. Следующий метод, JDBCTutorialUtilities.cursorHoldabilitySupport, выводит курсор значения по умолчанию holdability ResultSet объекты и ли HOLD_CURSORS_OVER_COMMIT и CLOSE_CURSORS_AT_COMMIT поддерживаются:

public static void cursorHoldabilitySupport(Connection conn)
    throws SQLException {

    DatabaseMetaData dbMetaData = conn.getMetaData();
    System.out.println("ResultSet.HOLD_CURSORS_OVER_COMMIT = " +
        ResultSet.HOLD_CURSORS_OVER_COMMIT);

    System.out.println("ResultSet.CLOSE_CURSORS_AT_COMMIT = " +
        ResultSet.CLOSE_CURSORS_AT_COMMIT);

    System.out.println("Default cursor holdability: " +
        dbMetaData.getResultSetHoldability());

    System.out.println("Supports HOLD_CURSORS_OVER_COMMIT? " +
        dbMetaData.supportsResultSetHoldability(
            ResultSet.HOLD_CURSORS_OVER_COMMIT));

    System.out.println("Supports CLOSE_CURSORS_AT_COMMIT? " +
        dbMetaData.supportsResultSetHoldability(
            ResultSet.CLOSE_CURSORS_AT_COMMIT));
}

Получение Значений столбцов от Строк

ResultSet интерфейс объявляет методы метода get (например, getBoolean и getLong) для того, чтобы получить значения столбцов от текущей строки. Можно получить значения, используя или индекс столбца или псевдоним или имя столбца. Столбец индексирует, обычно более эффективно. Столбцы нумеруются от 1. Для максимальной мобильности столбцы набора результатов в каждой строке должны быть считаны в слева направо порядке, и каждый столбец должен быть только для чтения однажды.

Например, следующий метод, CoffeesTable.alternateViewTable, получает значения столбцов числом:

public static void alternateViewTable(Connection con)
    throws SQLException {

    Statement stmt = null;
    String query =
        "select COF_NAME, SUP_ID, PRICE, " +
        "SALES, TOTAL from COFFEES";

    try {
        stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery(query);
        while (rs.next()) {
            String coffeeName = rs.getString(1);
            int supplierID = rs.getInt(2);
            float price = rs.getFloat(3);
            int sales = rs.getInt(4);
            int total = rs.getInt(5);
            System.out.println(coffeeName + "\t" + supplierID +
                               "\t" + price + "\t" + sales +
                               "\t" + total);
        }
    } catch (SQLException e ) {
        JDBCTutorialUtilities.printSQLException(e);
    } finally {
        if (stmt != null) { stmt.close(); }
    }
}

Строки, привыкшие как входной к методам метода get, являются нечувствительными к регистру. Когда метод метода get вызывают со строкой, и больше чем у одного столбца есть тот же самый псевдоним или имя как строка, значение первого столбца соответствия возвращается. Опция, чтобы использовать строку в противоположность целому числу разрабатывается, чтобы использоваться, когда псевдонимы столбца и имена используются в SQL-запросе, который генерировал набор результатов. Для столбцов, которые явно не называют в запросе (например, select * from COFFEES) лучше использовать номера столбца. Если имена столбцов будут использоваться, то разработчик должен гарантировать, что они уникально обращаются к намеченным столбцам при использовании псевдонимов столбца. Псевдоним столбца эффективно переименовывает столбец набора результатов. Чтобы определить псевдоним столбца, используйте SQL AS пункт в SELECT оператор.

Метод метода get соответствующего типа получает значение в каждом столбце. Например, в методе CoffeeTables.viewTable, первый столбец в каждой строке ResultSet rs COF_NAME, который хранит значение типа SQL VARCHAR. Метод для того, чтобы получить значение типа SQL VARCHAR getString. Второй столбец в каждой строке хранит значение типа SQL INTEGER, и метод для того, чтобы получить значения того типа getInt.

Отметьте это хотя метод getString рекомендуется для того, чтобы получить типы SQL CHAR и VARCHAR, возможно получить любой из основных типов SQL с этим. Получение всех значений с getString может быть очень полезным, но у этого также есть свои ограничения. Например, если это используется, чтобы получить числовой тип, getString преобразовывает числовое значение в Java String объект, и значение должны быть преобразованы назад в числовой тип прежде, чем на этом можно будет управлять как число. В случаях, где значение обрабатывается как строка так или иначе, нет никакого недостатка. Кроме того, если Вы хотите, чтобы приложение получило значения какого-либо стандартного типа SQL кроме типов SQL3, используйте getString метод.

Курсоры

Как упомянуто ранее, Вы получаете доступ к данным в a ResultSet объект через курсор, который указывает на одну строку в ResultSet объект. Однако, когда a ResultSet объект сначала создается, курсор располагается перед первой строкой. Метод CoffeeTables.viewTable перемещает курсор, вызывая ResultSet.next метод. Есть другие методы, доступные, чтобы переместить курсор:

Отметьте что чувствительность значения по умолчанию a ResultSet TYPE_FORWARD_ONLY, что означает, что это не может быть прокручено; невозможно вызвать ни один из этих методов, которые перемещают курсор, кроме next, если Ваш ResultSet не может быть прокручен. Метод CoffeesTable.modifyPrices, описанный в следующем разделе, демонстрирует, как можно переместить курсор a ResultSet.

Обновление Строк в Объектах ResultSet

Невозможно обновить значение по умолчанию ResultSet объект, и можно только переместить его курсор вперед. Однако, можно создать ResultSet объекты, которые могут быть прокручены (курсор может переместиться назад или переместиться в абсолютную позицию), и обновленный.

Следующий метод, CoffeesTable.modifyPrices, умножается PRICE столбец каждой строки параметром percentage:

public void modifyPrices(float percentage) throws SQLException {

    Statement stmt = null;
    try {
        stmt = con.createStatement();
        stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
                   ResultSet.CONCUR_UPDATABLE);
        ResultSet uprs = stmt.executeQuery(
            "SELECT * FROM " + dbName + ".COFFEES");

        while (uprs.next()) {
            float f = uprs.getFloat("PRICE");
            uprs.updateFloat( "PRICE", f * percentage);
            uprs.updateRow();
        }

    } catch (SQLException e ) {
        JDBCTutorialUtilities.printSQLException(e);
    } finally {
        if (stmt != null) { stmt.close(); }
    }
}

Поле ResultSet.TYPE_SCROLL_SENSITIVE создает a ResultSet возразите, чей курсор может переместить обоих вперед и назад относительно текущей позиции и к абсолютной позиции. Поле ResultSet.CONCUR_UPDATABLE создает a ResultSet объект, который может быть обновлен. См. ResultSet Javadoc для других полей можно определить, чтобы изменить поведение ResultSet объекты.

Метод ResultSet.updateFloat обновляет указанный столбец (в этом примере, PRICE с указанным float значение в строке, где курсор располагается. ResultSet содержит различные updater методы, которые позволяют Вам обновить значения столбцов различных типов данных. Однако, ни один из этих updater методов не изменяет базу данных; следует вызвать метод ResultSet.updateRow обновить базу данных.

Используя Объекты Оператора для Пакетных обновлений

Statement, PreparedStatement и CallableStatement у объектов есть список команд, который связывается с ними. Этот список может содержать операторы для того, чтобы обновить, вставить, или удалить строку; и это может также содержать операторы DDL такой как CREATE TABLE и DROP TABLE. Это не может, однако, содержать оператор, который произвел бы a ResultSet объект, такой как a SELECT оператор. Другими словами список может содержать только операторы, которые производят количество обновления.

Список, который связывается с a Statement объект при его создании, первоначально пусто. Можно добавить команды SQL к этому списку с методом addBatch и освободите это с методом clearBatch. Когда Вы закончили добавлять операторы к списку, вызовите метод executeBatch передаться им всем к базе данных, которая будет выполняться как модуль, или пакет.

Например, следующий метод CoffeesTable.batchUpdate добавляют четыре строки к COFFEES таблица с пакетным обновлением:

public void batchUpdate() throws SQLException {

    Statement stmt = null;
    try {
        this.con.setAutoCommit(false);
        stmt = this.con.createStatement();

        stmt.addBatch(
            "INSERT INTO COFFEES " +
            "VALUES('Amaretto', 49, 9.99, 0, 0)");

        stmt.addBatch(
            "INSERT INTO COFFEES " +
            "VALUES('Hazelnut', 49, 9.99, 0, 0)");

        stmt.addBatch(
            "INSERT INTO COFFEES " +
            "VALUES('Amaretto_decaf', 49, " +
            "10.99, 0, 0)");

        stmt.addBatch(
            "INSERT INTO COFFEES " +
            "VALUES('Hazelnut_decaf', 49, " +
            "10.99, 0, 0)");

        int [] updateCounts = stmt.executeBatch();
        this.con.commit();

    } catch(BatchUpdateException b) {
        JDBCTutorialUtilities.printBatchUpdateException(b);
    } catch(SQLException ex) {
        JDBCTutorialUtilities.printSQLException(ex);
    } finally {
        if (stmt != null) { stmt.close(); }
        this.con.setAutoCommit(true);
    }
}

Следующая строка отключает режим автоматической фиксации для Connection возразите доводу "против" так, чтобы транзакция автоматически не фиксировалась или откатывалась когда метод executeBatch вызывается.

this.con.setAutoCommit(false);

Чтобы учесть корректную обработку ошибок, следует всегда отключать режим автоматической фиксации прежде, чем начать пакетное обновление.

Метод Statement.addBatch добавляет команда к списку команд, связанных с Statement объект stmt. В этом примере эти команды - все INSERT INTO операторы, каждый добавляющий строку, состоящую из пяти значений столбцов. Значения для столбцов COF_NAME и PRICE имя кофе и его цены, соответственно. Второе значение в каждой строке 49, потому что это - идентификационный номер для поставщика, Превосходящего Кофе. Последние два значения, записи для столбцов SALES и TOTAL, все начинают быть нулем, потому что еще не было никаких продаж. (SALES число фунтов кофе этой строки, проданного на текущей неделе; TOTAL общее количество всех совокупных продаж этого кофе.)

Следующая строка отправляет четыре команды SQL, которые были добавлены к его списку команд к базе данных, которая будет выполняться как пакет:

int [] updateCounts = stmt.executeBatch();

Отметьте это stmt использует метод executeBatch отправить пакет вставок, не метод executeUpdate, который отправляет только одну команду и возвращает единственное количество обновления. DBMS выполняет команды в порядке, в котором они были добавлены к списку команд, таким образом, это сначала добавит строку значений для Amaretto, затем добавьте строку для Лесного ореха, тогда кофе без кофеина Amaretto, и наконец кофе без кофеина Лесного ореха. Если все четыре команды выполнятся успешно, то DBMS возвратит счет обновления для каждой команды в порядке, в котором это выполнялось. Количества обновления, которые указывают, на сколько строк влияла каждая команда, сохранены в массиве updateCounts.

Если все четыре из команд в пакете выполняются успешно, updateCounts будет содержать четыре значения, все из которых 1, потому что вставка влияет на одну строку. Список команд, связанных с stmt теперь будет пусто, потому что эти четыре команды, добавленные ранее, были отправлены базе данных когда stmt названный методом executeBatch. Можно в любое время явно освободить этот список от команд с методом clearBatch.

Connection.commit метод делает пакет из обновлений к COFFEES постоянная таблица. Этот метод нужно вызвать явно, потому что режим автоматической фиксации для этого соединения был отключен ранее.

Следующая строка включает режиму автоматической фиксации для тока Connection объект.

this.con.setAutoCommit(true);

Теперь каждый оператор в примере будет автоматически фиксироваться после того, как это будет выполнено, и это больше не должно вызвать метод commit.

Выполнение Параметризованного Пакетного обновления

Также возможно иметь параметризованное пакетное обновление, как показано в следующем фрагменте кода, где con a Connection объект:

con.setAutoCommit(false);
PreparedStatement pstmt = con.prepareStatement(
                              "INSERT INTO COFFEES VALUES( " +
                              "?, ?, ?, ?, ?)");
pstmt.setString(1, "Amaretto");
pstmt.setInt(2, 49);
pstmt.setFloat(3, 9.99);
pstmt.setInt(4, 0);
pstmt.setInt(5, 0);
pstmt.addBatch();

pstmt.setString(1, "Hazelnut");
pstmt.setInt(2, 49);
pstmt.setFloat(3, 9.99);
pstmt.setInt(4, 0);
pstmt.setInt(5, 0);
pstmt.addBatch();

// ... and so on for each new
// type of coffee

int [] updateCounts = pstmt.executeBatch();
con.commit();
con.setAutoCommit(true);

Обработка Исключений Пакетного обновления

Вы получите a BatchUpdateException когда Вы вызываете метод executeBatch если (1) один из SQL-операторов, которые Вы добавили к пакету, производит набор результатов (обычно запрос) или (2), один из SQL-операторов в пакете не выполняется успешно по некоторой другой причине.

Недопустимо добавить запрос (a SELECT оператор) к пакету команд SQL, потому что метод executeBatch, то, который возвращает массив количеств обновления, ожидает количество обновления от каждого SQL-оператора, который выполняется успешно. Это означает, что только команды, которые возвращают количество обновления (команды такой как INSERT INTO, UPDATE, DELETE) или тот возврат 0 (такой как CREATE TABLE, DROP TABLE, ALTER TABLE) может быть успешно выполнен как пакет с executeBatch метод.

A BatchUpdateException содержит массив количеств обновления, который подобен массиву, возвращенному методом executeBatch. В обоих случаях количества обновления находятся в том же самом порядке как команды, которые произвели их. Это говорит Вам, сколько команд в пакете, выполняемом успешно и которые они. Например, если пять команд выполнились успешно, массив будет содержать пять чисел: первый, являющийся обновлением, значит первую команду, второй, являющийся обновлением, значат вторую команду, и так далее.

BatchUpdateException получается из SQLException. Это означает, что можно использовать все методы, доступные SQLException объект с этим. Следующий метод, JDBCTutorialUtilities.printBatchUpdateException печатные издания весь из SQLException информация плюс количества обновления содержится в a BatchUpdateException объект. Поскольку BatchUpdateException.getUpdateCounts возвращает массив int, код использует a for цикл, чтобы напечатать каждое из количеств обновления:

public static void printBatchUpdateException(BatchUpdateException b) {

    System.err.println("----BatchUpdateException----");
    System.err.println("SQLState:  " + b.getSQLState());
    System.err.println("Message:  " + b.getMessage());
    System.err.println("Vendor:  " + b.getErrorCode());
    System.err.print("Update counts:  ");
    int [] updateCounts = b.getUpdateCounts();

    for (int i = 0; i < updateCounts.length; i++) {
        System.err.print(updateCounts[i] + "   ");
    }
}

Вставка Строк в Объектах ResultSet

Отметьте: Не вся поддержка драйверов JDBC, вставляющая новые строки с ResultSet интерфейс. Если Вы пытаетесь вставить новую строку, и Ваша база данных драйвера JDBC не поддерживает эту функцию, a SQLFeatureNotSupportedException исключение выдается.

Следующий метод, CoffeesTable.insertRow, вставляет строку в COFFEES через a ResultSet объект:

public void insertRow(String coffeeName, int supplierID,
                      float price, int sales, int total)
    throws SQLException {

    Statement stmt = null;
    try {
        stmt = con.createStatement(
            ResultSet.TYPE_SCROLL_SENSITIVE
            ResultSet.CONCUR_UPDATABLE);

        ResultSet uprs = stmt.executeQuery(
            "SELECT * FROM " + dbName +
            ".COFFEES");

        uprs.moveToInsertRow();
        uprs.updateString("COF_NAME", coffeeName);
        uprs.updateInt("SUP_ID", supplierID);
        uprs.updateFloat("PRICE", price);
        uprs.updateInt("SALES", sales);
        uprs.updateInt("TOTAL", total);

        uprs.insertRow();
        uprs.beforeFirst();
    } catch (SQLException e ) {
        JDBCTutorialUtilities.printSQLException(e);
    } finally {
        if (stmt != null) { stmt.close(); }
    }
}

Этот пример вызывает Connection.createStatement метод с двумя параметрами, ResultSet.TYPE_SCROLL_SENSITIVE и ResultSet.CONCUR_UPDATABLE. Первое значение включает курсору ResultSet объект, который будет перемещен оба вперед и назад. Второе значение, ResultSet.CONCUR_UPDATABLE, требуется, если Вы хотите вставить строки в a ResultSet объект; это определяет, что может быть обновляемо.

Те же самые соглашения для того, чтобы использовать строки в методах метода get также применяются к updater методам.

Метод ResultSet.moveToInsertRow перемещает курсор в строку вставки. Строка вставки является специальной строкой, связанной с обновляемым набором результатов. Это - по существу буфер, где новая строка может быть создана, вызывая updater методы до вставки строки в набор результатов. Например, это вызовы метода метод ResultSet.updateString обновить строку вставки COF_NAME столбец к Kona.

Метод ResultSet.insertRow вставляет содержание строки вставки в ResultSet возразите и в базу данных.

Отметьте: После вставки строки с ResultSet.insertRow, следует переместить курсор в строку кроме строки вставки. Например, этот пример перемещает это в перед первой строкой в наборе результатов с методом ResultSet.beforeFirst. Неожиданные результаты могут произойти, если другая часть Вашего приложения использует тот же самый набор результатов, и курсор все еще указывает на строку вставки.


Проблемы с примерами? Попытайтесь Компилировать и Выполнить Примеры: FAQ.
Жалобы? Поздравление? Предложения? Дайте нам свою обратную связь.

Предыдущая страница: Установка Таблиц
Следующая страница: Используя Готовые Операторы



Spec-Zone.ru - all specs in one place