1. Кастомізація 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);

Глибоко ці речі ми не будемо вивчати, але я хочу, щоб ти знав, що таке можливо, якщо зустрінеш щось схоже в чужому коді.

2. Типи 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 цього типу.

3. 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 може бути прочитаний та змінений.

4. Приклад зміни даних у базі

За допомогою цих параметрів ти можеш керувати створюваним 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().

Потім потрібно викликати метод insertRow(), щоб рядок додався до бази.

Ну і нарешті потрібно повернути курсор назад викликом методу moveToCurrentRow().

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