Кастомизация ResultSet

Современный JDBC API позволяет очень сильно кастомизировать объекты Statement и ResultSet. Например, с помощью ResultSet можно менять строки в базе данных.

При создании объекта statement в него можно передать кучу наших пожеланий. Эти пожелания можно разделить на три группы:

  • Тип связи с базой
  • Управление одновременным доступом
  • Сохраняемость и транзакции

Эти параметры можно передавать при создании объекта 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

ResultSet может быть определенного типа. Тип определяет некоторые характеристики и возможности ResultSet.

Не все типы поддерживаются всеми базами данных и драйверами JDBC. Тебе придется проверить свою базу данных и драйвер JDBC, чтобы увидеть, поддерживает ли он тип, который ты хочешь использовать. Метод DatabaseMetaData.supportsResultSetType(int type) возвращает true или false в зависимости от того, поддерживается данный тип или нет.

На момент написания статьи существует три типа ResultSet:

  • ResultSet.TYPE_FORWARD_ONLY
  • ResultSet.TYPE_SCROLL_INSENSITIVE
  • ResultSet.TYPE_SCROLL_SENSITIVE

Тип по умолчанию — TYPE_FORWARD_ONLY.

TYPE_FORWARD_ONLY означает, что ResultSet можно перемещать только вперед. То есть ты можешь перемещаться только из строки 1, строки 2, строки 3 и т. д. В ResultSet ты не можешь двигаться назад: нельзя считать данные из 9-й строки после чтения десятой.

TYPE_SCROLL_INSENSITIVE означает, что ResultSet можно перемещать (прокручивать) как вперед, так и назад. Ты также можешь перейти к позиции относительно текущей позиции или перейти к абсолютной позиции.

ResultSet этого типа нечувствителен к изменениям в базовом источнике данных, пока ResultSet открыт. То есть если запись в ResultSet изменяется в базе данных другим потоком или процессом, она не будет отражена в уже открытых ResultSet этого типа.

TYPE_SCROLL_SENSITIVE означает, что ResultSet можно перемещать (прокручивать) как вперед, так и назад. Ты также можешь перейти к позиции относительно текущей позиции или перейти к абсолютной позиции.

ResultSet этого типа чувствителен к изменениям в базовом источнике данных, пока ResultSet открыт. То есть если запись в ResultSet изменяется в базе данных другим потоком или процессом, она будет отражена в уже открытых ResultSet этого типа.

Concurrency

Параллельность ResultSet определяет, может ли ResultSet обновляться, или только считываться.

Некоторые базы данных и драйверы JDBC поддерживают обновление ResultSet, но не все. Метод DatabaseMetaData.supportsResultSetConcurrency(int concurrency) возвращает значение true или false в зависимости от того, поддерживается данный режим параллелизма или нет.

ResultSet может иметь один из двух уровней параллелизма:

  • ResultSet.CONCUR_READ_ONLY
  • ResultSet.CONCUR_UPDATABLE

CONCUR_READ_ONLY означает, что ResultSet может быть только прочитан.

CONCUR_UPDATABLE означает, что ResultSet может быть прочитан и изменен.

Пример изменения данных в базе

С помощью этих параметров ты можешь управлять создаваемым Statement и его ResultSet.

Например, можно создать обновляемый ResultSet и с его помощью менять базу данных. При создании Statement важно соблюсти следующие условия:

  • указывается только одна таблица
  • не содержит предложений join или group by
  • столбцы запроса должны содержать первичный ключ

При выполнении вышеуказанных условий обновляемый ResultSet может быть использован для модификации таблицы в базе данных. При создании объекта Statement нужно указать такие параметры:


 Statement st = createStatement(Result.TYPE_SCROLL_INSENSITIVE, Result.CONCUR_UPDATABLE)

Результатом выполнения такого оператора является обновляемый набор результатов. Метод обновления заключается в перемещении курсора ResultSet в строку, которую ты хочешь обновить, а затем в вызове метода updateXXX().

Метод updateXXX работает аналогично методу getXXX(). Метод updateXXX() имеет два параметра. Первый — это номер обновляемого столбца, который может быть именем столбца или серийным номером. Второй — это данные, которые необходимо обновить, и этот тип данных должен быть тот же, что и XXX.

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

Также можно добавлять новые строки в таблицу:

Сначала нужно переместить курсор на пустую строку. Для этого нужно вызвать метод moveToInsertRow().

Затем нужно заполнить эту строку данными с помощью метода updateXXX().

Затем нужно вызвать метод inserRow(), чтобы строка добавилась в базу.

Ну и наконец нужно вернуть курсор обратно, вызвав метод moveToCurrentRow().

Важно! Не все СУБД поддерживают данные параметры для расширенного оператора Statement. В случае наличия проблем смотри официальную документацию конкретной СУБД.