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() и затем читать данные из третьего параметра с помощью методa getInt().
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.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ