1. CallableStatement

У JDBC є ще один інтерфейс для більш складних сценаріїв. Він успадкований від PreparedStatement і називається CallableStatement.

Він використовується для виклику (Call) процедур, що зберігаються в базі даних. Особливість такого виклику в тому, що крім результату ResultSet такій процедурі, що зберігається, можна ще й передати параметри.

А що тут нового, спитаєш ти? PreparedStatement теж має результат ResultSet, і до нього також можна передавати параметри. Так, все вірно, але особливість процедур, що зберігаються в тому, що через параметри вони можуть не лише отримувати, а й повертати дані.

Збережена процедура викликається з параметрами IN, OUT та INOUT. Вона повертає один або кілька об'єктів ResultSet. Для створення об'єкта CallableStatement призначений метод Connection.prepareCall().

Ось уяви, що в тебе є процедура ADD, що зберігається, яка приймає параметри a, b і c. Ця процедура складає a та b й поміщає результат додавання до змінної с.

Давай напишемо код, де спробуємо її викликати:


 // Підключення до сервера
 Connection connection = DriverManager.getConnection("jdbc:as400://mySystem");
 
 // Створення об'єкта CallableStatement. Він виконує попередню обробку
 // виклику процедури, що зберігається. Знаки питання
 // вказують, де треба підставити вхідні параметри, а де вихідні
 // Перші два параметри є вхідними,
 // а третій — вихідним.
 CallableStatement statement = connection.prepareCall("CALL MYLIBRARY.ADD(?, ?, ?)");
 
 // Налаштування вхідних параметрів. Передаємо до процедури 123 та 234
 statement.setInt (1, 123);
 statement.setInt (2, 234);
 
 // Реєстрація типу вихідного параметра
 statement.registerOutParameter (3, Types.INTEGER);
 
 // Запуск процедури, що зберігається
 statement.execute();
 
 // Отримання значення вихідного параметра
 int sum = statement.getInt(3);
 
 // Закриття CallableStatement та Connection
 statement.close();
 connection.close();

Робота майже як з PreparedStatement, тільки є нюанс. Наша функція ADD повертає у третьому параметрі результат додавання. Тільки об'єкт CallableStatement про це нічого не знає. Тому ми говоримо йому про це явно, за допомогою виклику методу registerOutParameter():


registerOutParameter(номерПараметра, типПараметра)

Після цього можна викликати процедуру методом execute() і потім читати дані з третього параметра за допомогою методу getInt ().

2. Batching запитів

У реальних проектах часто виникає ситуація, коли необхідно зробити дуже багато однотипних запитів (найчастіше в цьому випадку зустрічається PreparedStatement). Наприклад, треба вставити кілька десятків або сотень записів.

Якщо виконувати кожен запит окремо, це займе купу часу і знизить продуктивність програми. Щоб запобігти цьому, можна використовувати batch-режим вставлення. Він полягає в тому, що ти накопичуєш деякий буфер своїми запитами, а потім виконуєш їх одразу.

Як приклад наведу шматочок коду:


PreparedStatement stmt = con.prepareStatement(
        "INSERT INTO jc_contact (first_name, last_name, phone, email) VALUES (?, ?, ?, ?)");
 
for (int i = 0; i < 10; i++) {
// Заповнюємо параметри запиту
stmt.setString(1, "FirstName_" + i);
    stmt.setString(2, "LastNAme_" + i);
    stmt.setString(3, "phone_" + i);
    stmt.setString(4, "email_" + i);
// Запит не виконується, а вкладається в буфер,
// який потім виконується одразу для всіх команд
stmt.addBatch();
}
// Виконуємо всі запити разом
int[] results = stmt.executeBatch();

Замість виконання запиту execute() ми складаємо його в пакет за допомогою методу addBatch( ).

А потім, коли набралося кілька сотень запитів, можна їх разом надіслати на сервер викликом команди executeBatch().

Корисно. Метод executeBatch() повертає масив цілих чисел — int[]. Кожна ячейка цього масиву містить число, яке означає кількість рядків, змінених відповідним запитом. Якщо запит номер 3 у batch-і змінив 5 рядків, то 3-тя ячейка масиву міститиме число 5.