Ответ
CallableStatement — это интерфейс в JDBC API, предназначенный для выполнения хранимых процедур и функций, вызываемых из базы данных. Он наследует от PreparedStatement и поддерживает параметры типов IN (входные), OUT (выходные) и INOUT (входо-выходные).
Пример вызова хранимой процедуры с OUT-параметром:
// Предположим, есть процедура: CREATE PROCEDURE get_employee_name(IN emp_id INT, OUT emp_name VARCHAR(100))
String sql = "{call get_employee_name(?, ?)}"; // Синтаксис вызова процедуры
try (Connection conn = dataSource.getConnection();
CallableStatement stmt = conn.prepareCall(sql)) {
// Установка IN-параметра
stmt.setInt(1, 123);
// Регистрация OUT-параметра (указание его типа)
stmt.registerOutParameter(2, Types.VARCHAR);
// Выполнение процедуры
stmt.execute();
// Получение значения OUT-параметра после выполнения
String employeeName = stmt.getString(2);
System.out.println("Employee name: " + employeeName);
} catch (SQLException e) {
e.printStackTrace();
}
Основные особенности и преимущества:
- Производительность: Хранимые процедуры часто выполняются быстрее, так как компилируются и кэшируются на стороне СУБД.
- Бизнес-логика на стороне БД: Позволяет инкапсулировать сложную логику работы с данными внутри базы.
- Безопасность: Может помочь предотвратить SQL-инъекции и предоставить более строгий контроль доступа.
- Работа с REF CURSOR: Поддерживает возврат результирующих наборов через курсоры.
- Множественные результаты: Может возвращать несколько результирующих наборов (используется
stmt.getMoreResults()).
Ответ 18+ 🔞
Слушай, а вот этот ваш CallableStatement — это же, блядь, такая специальная штука в JDBC, чтобы с хранимыми процедурами в базе общаться! Ну, типа, не просто тупой SELECT гонять, а вызвать там какую-нибудь навороченную логику, которую админы-садисты прямо в недрах СУБД записали. Наследует он от PreparedStatement, так что все плюшки вроде защиты от инъекций на месте, но ещё умеет параметры IN, OUT и INOUT обрабатывать. Представляешь? Ты ему номер сотрудника суёшь (IN), а он тебе после выполнения имя из базы вытаскивает (OUT) — магия, ёпта!
Вот смотри, как это выглядит в коде, если не хочешь, чтобы тебя потом за такое на хуй послали:
// Допустим, в базе валяется процедура: CREATE PROCEDURE get_employee_name(IN emp_id INT, OUT emp_name VARCHAR(100))
String sql = "{call get_employee_name(?, ?)}"; // Вот этот фигурный синтаксис, блядь, обязателен!
try (Connection conn = dataSource.getConnection();
CallableStatement stmt = conn.prepareCall(sql)) {
// Засовываем входной параметр (IN) — ID сотрудника
stmt.setInt(1, 123);
// А вот это важно, ёбта! Говорим джаве: "Слушай, второй параметр — выходной, текстовый, готовься его ловить!"
stmt.registerOutParameter(2, Types.VARCHAR);
// Поехали! Запускаем процедуру. База там своё колдует...
stmt.execute();
// Всё, процедура отработала. Теперь можно вытащить результат из OUT-параметра.
String employeeName = stmt.getString(2);
System.out.println("Employee name: " + employeeName); // Ну вот и имя, сука!
} catch (SQLException e) {
e.printStackTrace(); // А тут, как водится, может всё накрыться медным тазом.
}
И зачем этот геморрой, спросишь? А вот зачем, хитрая жопа:
- Скорость, блядь! Процедуры на стороне базы уже скомпилированы, они часто быстрее, чем гонять туда-сюда километровые SQL-скрипты.
- Логика в одном месте. Вся бизнес-муть может сидеть прямо в базе. Для админов — сказка, для разработчиков — иногда ад, но что поделать.
- Безопасность. Ну, в плане инъекций там всё прикрыто, да и права можно на процедуры навесить, а не на таблицы.
- Возврат целых наборов данных (REF CURSOR). Может не просто имя вернуть, а целую таблицу результатов! Правда, выковыривать её — ещё то удовольствие.
- Множественные результаты. Одна процедура может навернуть несколько сетов данных подряд. Чтобы всё это переварить, надо
getMoreResults()юзать — волнение ебать, но работает.
Короче, инструмент мощный, но если накосячить с регистрацией OUT-параметров — получишь SQLException такой, что мало не покажется. Так что, блядь, думай головой, когда вызываешь!