Руководство по JDBC. Result Set.

В прошлом уроке мы рассмотрели понятие Statements и их виды. Мы узнали, что в результате SQL – запроса мы получаем данные.

Данные, полученные в результате SQL – запроса возвращаются в виде множества результатов, которые хранятся в сущности под названием Result Set.

Стандартный способ получить записи из нашей базе данных (далее – БД) – это применение ключевого слова SELECT. Стандартный способ просмотреть эти данные – это использовать Result set.

Интерфейс java.sql.ResultSet представляет собой множество результатов, запроса в БД.

Экземпляр ResultSet имеет указатель, который указывает на текущую строку в полученном множестве.

Все методы интерфейса java.sql.ResultSet мы можем разделить на три большие группы:

  • Методы получения данных.
    Эти методы используются для просмотра данных конкретной записи, на которую ссылается указатель.
  • Методы изменения данных.
    Методы этой группы используются для изменения данных текущей записи. Эти изменения передаются в используемую БД.
  • Методы навигации.
    Эти методы используются для перемещения указателя.

Курсор двигается на основе свойств ResultSet. Эти свойства указываются при создании экземпляра ResultSet.

Для определения этих свойств используются следующие методы:

  • createStatement (int RSType, int RSConcurrency);
  • prepareStatement (String SQL, int RSType, int RSConcurrency);
  • prepareCall (String SQL, int RSType, int RSConcurrency);

Аргумент RSType определяет тип ResultSet, а второй – определяет, используется ли данный экземпляр ResultSet только для чтения, или для чтения и изменения также.


Типы ResultSet

Возможные типы ResultSet приведены ниже. Тип TYPE_FORWARD_ONLY используется по умолчанию.

Рассмотрим эти типы:

  • ResultSet.TYPE-FORWARD_ONLY
    Указатель двигается только вперёд по множеству полученных результатов.
    .
  • ResultSet.TYPE_SCROLL_INSENSITIVE
    Указатель может двигаться вперёд и назад и не чувствителен к изменениям в БД, которые сделаны другими пользователями после того, как ResultSet был создан.
  • ResultSet.TYPE_SCROLL_SENSITIVE
    Указатель может двигаться вперёд и назад и чувствителен к изменениям в БД, которые сделаны другими пользователями после того, как ResultSet был создан.

Доступ ResultSet

По умолчанию RSConcurrency экземпляра ResultSet установлен тип CONCUR_READ_ONLY, т.е. только для чтения.

Всего существует два типа этого параметра:

  • ResultSet.CONCUR_READ_ONLY
    Создаёт экземпляр ResultSet только для чтения. Устанавливается по умолчанию.
  • ResultSet.CONCUR_UPDATABLE
    Создаёт экземпляр ResultSet, который может изменять данные.

В виде кода, создание экземпляра ResultSet с необходимыми нам параметрами выглядит, примерно так:


try {
            statement = connection.createStatement(
                    ResultSet.TYPE_FORWARD_ONLY,
                    ResultSet.CONCUR_READ_ONLY
            );
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            /*do some job*/
        }

Навигация по ResultSet

В интерфейсе java.sql.ResultSet существует несколько методов для перемещения указателя.

Некоторые из них приведены ниже:

  • public void beforeFirst () throws SQLException
    Перемещает указатель на место перед первым рядом.
  • public void afterLast () throws SQLException
    Перемещает указатель на место после крайнего ряда.
  • public boolean first () throws SQLException
    Перемещает указатель на первый ряд.
  • public boolean last () throws SQLException
    Перемещает указатель на крайний ряд.
  • public boolean previous () throws SQLException
    Перемещает указатель на предыдущий ряд. Возвращает false, если предыдущий ряд находится за пределами множества результатов.
  • public boolean next () throws SQLException
    Перемещает указатель на следующий ряд. Возвращает false, если следующий ряд находится за пределами множества результатов.
  • public void absolute (int row) throws SQLException
    Перемещает указатель на указанный ряд.
  • public void relative (int row) throws SQLException
    Перемещает указатель на указанное количество рядов от текущего
  • public int getRow () throws SQLException
    Возвращает номер ряда, на который в данный момент указывает курсор.
  • public void moveToInsertRow () throws SQLException
    Перемещает указатель на ряд в полученном множестве, который может быть использован для того, чтобы добавить новую запись в БД. Текущее положение указателя запоминается.
  • public void moveToCurrentRow () throws SQLExcpetion
    Возвращает указатель обратно на текущий ряд в случае, если указатель ссылается на ряд, в который в данный момент добавляются данные.

Для понимания того, как это работает на практике, рассмотрим пример простого приложения.


import java.sql.*;

public class ResultSetNavigationDemo {
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DATABASE_URL = "jdbc:mysql://localhost/PROSELYTE_TUTORIALS";

    static final String USER = "ВАШЕ_ИМЯ_ПОЛЬЗОВАТЕЛЯ";
    static final String PASSWORD = "ВАШ_ПАРОЛЬ";

    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Connection connection = null;
        Statement statement = null;

        Class.forName(JDBC_DRIVER);

        connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);

        System.out.println("Creating statement...");

        try {
            statement = connection.createStatement(
                    ResultSet.TYPE_FORWARD_ONLY,
                    ResultSet.CONCUR_UPDATABLE
            );
            String SQL = "SELECT * FROM developers";
            ResultSet resultSet = statement.executeQuery(SQL);

            System.out.println("Moving cursor to the last position...");
            resultSet.last();

            System.out.println("Getting record...");
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            String specialty = resultSet.getString("specialty");
            int salary = resultSet.getInt("salary");

            System.out.println("Last record in result set:");
            System.out.println("id: " + id);
            System.out.println("Name: " + name);
            System.out.println("Specialty: " + specialty);
            System.out.println("Salary: $" + salary);
            System.out.println("\n=========================\n");

            System.out.println("Moving cursor to previous row...");
            resultSet.previous();

            System.out.println("Getting record...");
            id = resultSet.getInt("id");
            name = resultSet.getString("name");
            specialty = resultSet.getString("specialty");
            salary = resultSet.getInt("salary");

            System.out.println("Previous record:");
            System.out.println("id: " + id);
            System.out.println("Name: " + name);
            System.out.println("Specialty: " + specialty);
            System.out.println("Salary: $" + salary);
            System.out.println("\n=========================\n");

            System.out.println("Moving cursor to the first row...");
            resultSet.first();

            System.out.println("Getting record...");
            id = resultSet.getInt("id");
            name = resultSet.getString("name");
            specialty = resultSet.getString("specialty");
            salary = resultSet.getInt("salary");

            System.out.println("First record:");
            System.out.println("id: " + id);
            System.out.println("Name: " + name);
            System.out.println("Specialty: " + specialty);
            System.out.println("Salary: $" + salary);
            System.out.println("\n=========================\n");

            System.out.println("Adding record...");
            SQL = "INSERT INTO developers VALUES (5, 'Mike', 'PHP', 1500)";
            statement.executeUpdate(SQL);

            SQL = "SELECT * FROM developers";
            resultSet = statement.executeQuery(SQL);
            resultSet.last();

            System.out.println("Getting record...");
            id = resultSet.getInt("id");
            name = resultSet.getString("name");
            specialty = resultSet.getString("specialty");
            salary = resultSet.getInt("salary");

            System.out.println("Last record:");
            System.out.println("id: " + id);
            System.out.println("Name: " + name);
            System.out.println("Specialty: " + specialty);
            System.out.println("Salary: $" + salary);
            System.out.println("\n=========================\n");


            System.out.println("Full list of records:");
            SQL = "SELECT * FROM developers";
            resultSet = statement.executeQuery(SQL);

            while (resultSet.next()) {
                id = resultSet.getInt("id");
                name = resultSet.getString("name");
                specialty = resultSet.getString("specialty");
                salary = resultSet.getInt("salary");

                System.out.println("id: " + id);
                System.out.println("Name: " + name);
                System.out.println("Specialty: " + specialty);
                System.out.println("Salary: $" + salary);
                System.out.println("\n=========================\n");

            }


        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
             if (statement != null) {
                statement.close();
            }
            if(connection!=null){
                connection.close();
            }
        }
    }
}

В результате работы программы мы получим, следующий результат:


/*Some System Messages*/

Creating statement...
Moving cursor to the last position...
Getting record...
Last record in result set:
id: 4
Name: Eugene
Specialty: Java
Salary: $3000

=========================

Moving cursor to previous row...
Getting record...
Previous record:
id: 3
Name: AsyaSmile
Specialty: UI/UX
Salary: $2000

=========================

Moving cursor to the first row...
Getting record...
First record:
id: 1
Name: Proselyte
Specialty: Java
Salary: $3000

=========================

Adding record...
Getting record...
Last record:
id: 5
Name: Mike
Specialty: PHP
Salary: $1500

=========================

Full list of records:
id: 1
Name: Proselyte
Specialty: Java
Salary: $3000

=========================

id: 2
Name: Peter
Specialty: C++
Salary: $3000

=========================

id: 3
Name: AsyaSmile
Specialty: UI/UX
Salary: $2000

=========================

id: 4
Name: Eugene
Specialty: Java
Salary: $3000

=========================

id: 5
Name: Mike
Specialty: PHP
Salary: $1500

=========================

Просмотр результатов ResultSet

Для получения и редактирования данных, в интерфейса ResultSet существует множество методов.

Мы можем получить данные, как по имени, так и индексу:

  • public int getInt (int columnIndex) throws SQLException
    Возвращает номер текущего ряда с указанным индексом колонки. Индексы начинаются с 1. Т.е. первая – 1, вторая – 2 и т.д.
  • public int getInt (String columnName) throws SQLException
    Возвращает целое число в текущем ряду с колонкой с именем, переданном в параметре columnName.

Существуют также методы для получения определённых типов данных SQL (java.sql.Time, java.sql.Date и т.д.).

Для понимания того, как это работает на практике, рассмотрим следующий пример.

Пример:


import java.sql.*;

public class ResultSetViewDemo {
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DATABASE_URL = "jdbc:mysql://localhost/PROSELYTE_TUTORIALS";

    static final String USER = "ВАШЕ_ИМЯ_ПОЛЬЗОВАТЕЛЯ";
    static final String PASSWORD = "ВАШ_ПАРОЛЬ";

    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Connection connection = null;
        Statement statement = null;

        Class.forName(JDBC_DRIVER);

        connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);

        System.out.println("Creating statement...");

        try {
            statement = connection.createStatement(
                    ResultSet.TYPE_FORWARD_ONLY,
                    ResultSet.CONCUR_UPDATABLE
            );
            String SQL = "SELECT * FROM developers";
            ResultSet resultSet = statement.executeQuery(SQL);

            System.out.println("Moving cursor to the last position...");
            resultSet.last();

            System.out.println("Getting record (by name)...");
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            String specialty = resultSet.getString("specialty");
            int salary = resultSet.getInt("salary");

            System.out.println("Last record in result set:");
            System.out.println("id: " + id);
            System.out.println("Name: " + name);
            System.out.println("Specialty: " + specialty);
            System.out.println("Salary: $" + salary);
            System.out.println("\n=========================\n");

            System.out.println("Moving cursor to previous row...");
            resultSet.previous();

            System.out.println("Getting record...");
            id = resultSet.getInt("id");
            name = resultSet.getString("name");
            specialty = resultSet.getString("specialty");
            salary = resultSet.getInt("salary");

            System.out.println("Previous record:");
            System.out.println("id: " + id);
            System.out.println("Name: " + name);
            System.out.println("Specialty: " + specialty);
            System.out.println("Salary: $" + salary);
            System.out.println("\n=========================\n");

            System.out.println("Moving cursor to the first row...");
            resultSet.first();

            System.out.println("Getting record...");
            id = resultSet.getInt("id");
            name = resultSet.getString("name");
            specialty = resultSet.getString("specialty");
            salary = resultSet.getInt("salary");

            System.out.println("First record:");
            System.out.println("id: " + id);
            System.out.println("Name: " + name);
            System.out.println("Specialty: " + specialty);
            System.out.println("Salary: $" + salary);
            System.out.println("\n=========================\n");

            System.out.println("Adding record...");
            SQL = "INSERT INTO developers VALUES (5, 'Mike', 'PHP', 1500)";
            statement.executeUpdate(SQL);

            SQL = "SELECT * FROM developers";
            resultSet = statement.executeQuery(SQL);
            resultSet.last();

            System.out.println("Getting record (by index)...");
            id = resultSet.getInt(1);
            name = resultSet.getString(2);
            specialty = resultSet.getString(3);
            salary = resultSet.getInt(4);

            System.out.println("Last record:");
            System.out.println("id: " + id);
            System.out.println("Name: " + name);
            System.out.println("Specialty: " + specialty);
            System.out.println("Salary: $" + salary);
            System.out.println("\n=========================\n");


            System.out.println("Full list of records (by name):");
            SQL = "SELECT * FROM developers";
            resultSet = statement.executeQuery(SQL);

            while (resultSet.next()) {
                id = resultSet.getInt("id");
                name = resultSet.getString("name");
                specialty = resultSet.getString("specialty");
                salary = resultSet.getInt("salary");

                System.out.println("id: " + id);
                System.out.println("Name: " + name);
                System.out.println("Specialty: " + specialty);
                System.out.println("Salary: $" + salary);
                System.out.println("\n=========================\n");

            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
}

В результате работы программы мы получим следующий результат:


/*Some System Messages*/

Creating statement...
Moving cursor to the last position...
Getting record (by name)...
Last record in result set:
id: 4
Name: Eugene
Specialty: Java
Salary: $3000

=========================

Moving cursor to previous row...
Getting record...
Previous record:
id: 3
Name: AsyaSmile
Specialty: UI/UX
Salary: $2000

=========================

Moving cursor to the first row...
Getting record...
First record:
id: 1
Name: Proselyte
Specialty: Java
Salary: $3000

=========================

Adding record...
Getting record (by index)...
Last record:
id: 5
Name: Mike
Specialty: PHP
Salary: $1500

=========================

Full list of records (by name):
id: 1
Name: Proselyte
Specialty: Java
Salary: $3000

=========================

id: 2
Name: Peter
Specialty: C++
Salary: $3000

=========================

id: 3
Name: AsyaSmile
Specialty: UI/UX
Salary: $2000

=========================

id: 4
Name: Eugene
Specialty: Java
Salary: $3000

=========================

id: 5
Name: Mike
Specialty: PHP
Salary: $1500

=========================

Редактирование данных ResultSet

Для редактирования данных, в интерфейсе java.sql.ResultSet, также разработано множество методов.

Мы можем изменять данные, как по имени, так и по индексу колонки:

  • public void updateString (int columnIndex, String s) throws SQLException
    Изменяет строку в указанной колонке.
  • public void updateString (String columnName, String s) throws SQLException
    Изменяет строку в колонке с указанным именем.

Мы также можем работать с рядами в таблице БД:

  • public void insertRow()
    Вставляет запись в таблицу БД. Может быть использован только в том случае, когда указатель ссылается на ряд для вставки.
  • public void updateRow()
    Изменяет текущий ряд в таблице БД.
  • public void deleteRow()
    Удаляет текущий ряд из таблицы БД.

Для понимания того, как это работает на практике, рассмотрим такой пример.

Пример:


import java.sql.*;

public class ResultSetUpdateDemo {
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DATABASE_URL = "jdbc:mysql://localhost/PROSELYTE_TUTORIALS";

    static final String USER = "ВАШЕ_ИМЯ_ПОЛЬЗОВАТЕЛЯ";
    static final String PASSWORD = "ВАШ_ПАРОЛЬ";

    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Connection connection = null;
        Statement statement = null;

        Class.forName(JDBC_DRIVER);

        connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);

        System.out.println("Creating statement...");

        try {
            statement = connection.createStatement(
                    ResultSet.TYPE_FORWARD_ONLY,
                    ResultSet.CONCUR_UPDATABLE
            );
            String SQL = "SELECT * FROM developers";
            ResultSet resultSet = statement.executeQuery(SQL);

            System.out.println("Initial list of records:");
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                String specialty = resultSet.getString("specialty");
                int salary = resultSet.getInt("salary");

                System.out.println("Last record in result set:");
                System.out.println("id: " + id);
                System.out.println("Name: " + name);
                System.out.println("Specialty: " + specialty);
                System.out.println("Salary: $" + salary);
                System.out.println("\n=========================\n");
            }

            System.out.println("Increasing all developer's salary (+ $1,000)...");
            resultSet.first();
            while (resultSet.next()) {
                int newSalary = resultSet.getInt("salary") + 1000;
                resultSet.updateInt("salary", newSalary);
                resultSet.updateRow();
            }

            resultSet.first();
            System.out.println("Final list of records:");
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                String specialty = resultSet.getString("specialty");
                int salary = resultSet.getInt("salary");

                System.out.println("id: " + id);
                System.out.println("Name: " + name);
                System.out.println("Specialty: " + specialty);
                System.out.println("Salary: $" + salary);
                System.out.println("\n=========================\n");
            }
            resultSet.close();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
}

В результате работы программы мы получим следующий результат:


Creating statement...
Initial list of records:
Last record in result set:
id: 1
Name: Proselyte
Specialty: Java
Salary: $3000

=========================

Last record in result set:
id: 2
Name: Peter
Specialty: C++
Salary: $3000

=========================

Last record in result set:
id: 3
Name: AsyaSmile
Specialty: UI/UX
Salary: $2000

=========================

Last record in result set:
id: 4
Name: Eugene
Specialty: Java
Salary: $3000

=========================

Last record in result set:
id: 5
Name: Mike
Specialty: PHP
Salary: $1500

=========================

Increasing all developer's salary (+ $1,000)...
Final list of records:
id: 2
Name: Peter
Specialty: C++
Salary: $4000

=========================

id: 3
Name: AsyaSmile
Specialty: UI/UX
Salary: $3000

=========================

id: 4
Name: Eugene
Specialty: Java
Salary: $4000

=========================

id: 5
Name: Mike
Specialty: PHP
Salary: $2500

=========================

В этом уроке мы изучили такой важный элемент, как ResultSet, его методы, применение и рассмотрели примеры приложений с его использованием.

В следующем уроке мы изучим типы данных JDBC.