Ответ
При создании 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.