Какие параметры можно настроить у ResultSet в JDBC?

Ответ

При создании Statement или PreparedStatement в JDBC можно настроить три ключевых параметра ResultSet, определяющих его поведение.

1. Тип курсора (ResultSet Type)

  • TYPE_FORWARD_ONLY (по умолчанию): Курсор движется только вперед.
  • TYPE_SCROLL_INSENSITIVE: Курсор может двигаться в любом направлении (previous(), absolute()), но не отражает изменения, сделанные другими транзакциями в базе данных после открытия ResultSet.
  • TYPE_SCROLL_SENSITIVE: Курсор скроллируется и отражает изменения в данных, сделанные другими транзакциями.

2. Режим конкурентности (Concurrency Mode)

  • CONCUR_READ_ONLY (по умолчанию): Набор результатов доступен только для чтения.
  • CONCUR_UPDATABLE: Данные в ResultSet можно обновлять, удалять или вставлять новые строки с помощью методов updateXXX(), updateRow(), deleteRow(), insertRow(). Поддержка зависит от СУБД и запроса.

3. Удержание курсора (Cursor Holdability) Определяет, остается ли ResultSet открытым после вызова Connection.commit().

  • HOLD_CURSORS_OVER_COMMIT: Курсоры остаются открытыми.
  • CLOSE_CURSORS_AT_COMMIT: Курсоры закрываются автоматически.

Пример создания настраиваемого Statement:

// Создание Statement с прокручиваемым и обновляемым ResultSet
Statement stmt = connection.createStatement(
    ResultSet.TYPE_SCROLL_INSENSITIVE,
    ResultSet.CONCUR_UPDATABLE
);
ResultSet rs = stmt.executeQuery("SELECT id, name FROM employees");

// Использование возможностей
rs.absolute(5); // Переход к 5-й строке
rs.updateString("name", "Новое Имя");
rs.updateRow(); // Фиксация изменения в БД

Важно: Поддержка CONCUR_UPDATABLE и TYPE_SCROLL_SENSITIVE зависит от драйвера базы данных и самого запроса (например, запрос к одной таблице обычно поддерживается).

Ответ 18+ 🔞

Давай разжую эту тему про ResultSet, а то некоторые думают, что это просто какая-то хуйня для чтения данных и всё. Нет, блядь, там целый театр с настройками, ёпта!

Вот смотри, когда ты создаёшь Statement или PreparedStatement в JDBC, тебе дают три рычага, чтобы настроить, как твой ResultSet будет себя вести. Это не просто так, это важно, а то потом удивляешься, почему rs.previous() не работает или почему после коммита всё накрылось медным тазом.

1. Тип курсора (ResultSet Type) – куда ползём?

  • TYPE_FORWARD_ONLY (дефолтный, как скучная жизнь): Курсор, сука, ползёт только вперёд. Как танк, заднюю не даёт. Проще говоря, прочитал строку – иди дальше, назад ходу нет.
  • TYPE_SCROLL_INSENSITIVE: А вот это уже интереснее. Курсор может и вперёд, и назад (previous(), absolute()), как мартышка по лианам. Но! Он НЕ ВИДИТ изменений, которые другие транзакции наделали в базе после того, как ты этот ResultSet открыл. Он как слепой, но очень подвижный.
  • TYPE_SCROLL_SENSITIVE: Это уже высший пилотаж. Курсор скроллится туда-сюда И отражает изменения в данных, которые другие натворили. Чувак с рентгеновским зрением, но поддержка этой фичи – хуй знает где, зависит от драйвера и БД.

2. Режим конкурентности (Concurrency Mode) – можем ли трогать?

  • CONCUR_READ_ONLY (опять дефолт): Набор результатов только для чтения. Смотри, но руками не трогай, экспонат.
  • CONCUR_UPDATABLE: А вот тут уже можно творить! Данные в самом ResultSet можно обновлять, удалять строки или даже новые вставлять, прямо через методы типа updateString(), updateRow(), deleteRow(). Представляешь? Но это, блядь, как ковёр-самолёт – все хотят, но работает не у всех и не всегда. Зависит от СУБД и от того, насколько простой у тебя запрос.

3. Удержание курсора (Cursor Holdability) – что после коммита? Вот это, блядь, часто пролетает мимо кассы. Определяет, останется ли твой ResultSet жить после того, как ты сделаешь connection.commit().

  • HOLD_CURSORS_OVER_COMMIT: Курсоры остаются открытыми. Коммитнулся, а данные в ResultSet всё ещё доступны.
  • CLOSE_CURSORS_AT_COMMIT: Как только коммит – все курсоры автоматом закрываются. Чистый, блядь, расчёт.

Ну и пример, чтобы не быть просто пиздаболом:

// Создаём Statement не дефолтный, а прокручиваемый и ОБНОВЛЯЕМЫЙ, вот это да!
Statement stmt = connection.createStatement(
    ResultSet.TYPE_SCROLL_INSENSITIVE, // Можем скроллить
    ResultSet.CONCUR_UPDATABLE         // И можем обновлять!
);
ResultSet rs = stmt.executeQuery("SELECT id, name FROM employees");

// Используем всю эту мощь
rs.absolute(5); // Прыгаем сразу на пятую строку, блядь!
rs.updateString("name", "Новое Имя"); // Меняем имя прямо в ResultSet
rs.updateRow(); // И БАМ! – фиксируем это изменение уже в самой базе данных.

И главное, на последок: Не обольщайся раньше времени. Поддержка CONCUR_UPDATABLE и особенно TYPE_SCROLL_SENSITIVE – это как удача в картах. Зависит полностью от драйвера твоей базы и от запроса (например, запрос к одной таблице без джойнов обычно прокатывает, а с сложными джойнами – хуй тебе, а не обновляемый результат). Всегда проверяй, что твоя СУБД это вообще умеет, а то будешь как дурак с методами, которые кидают SQLFeatureNotSupportedException.