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.

undefined
1
Задача
Модуль 4. Работа с БД, 8 уровень, 2 лекция
Недоступна
task0804
task0804