В чем разница между PreparedStatement и CallableStatement в JDBC?

Ответ

Оба интерфейса наследуются от Statement, но предназначены для разных целей.

PreparedStatement используется для выполнения параметризованных SQL-запросов (SELECT, INSERT, UPDATE, DELETE).

  • Основная цель: Безопасность (защита от SQL-инъекций) и производительность (прекомпиляция запроса).
  • Синтаксис: Использует плейсхолдеры ?.
  • Параметры: Только входные (IN).

Пример:

String sql = "UPDATE users SET email = ? WHERE id = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, "new@email.com"); // Установка параметров по индексу
pstmt.setInt(2, 123);
int rowsUpdated = pstmt.executeUpdate();

CallableStatement используется для вызова хранимых процедур или функций базы данных.

  • Основная цель: Работа с бизнес-логикой, инкапсулированной на стороне БД.
  • Синтаксис: Использует escape-последовательность {call ...}.
  • Параметры: Поддерживает входные (IN), выходные (OUT) и входо-выходные (INOUT) параметры.

Пример вызова процедуры с OUT-параметром:

// Процедура в БД: get_user_name(IN user_id INT, OUT user_name VARCHAR)
String sql = "{call get_user_name(?, ?)}";
CallableStatement cstmt = connection.prepareCall(sql);
cstmt.setInt(1, 123); // IN-параметр
cstmt.registerOutParameter(2, Types.VARCHAR); // Регистрация OUT-параметра
cstmt.execute();
String userName = cstmt.getString(2); // Получение значения OUT-параметра
Ключевые отличия: Критерий PreparedStatement CallableStatement
Назначение Параметризованный SQL Вызов хранимой процедуры/функции
Параметры Только IN (входные) IN, OUT, INOUT
Синтаксис "SELECT ... WHERE id = ?" "{call proc_name(?, ?)}"
Регистрация OUT Не требуется registerOutParameter()

Ответ 18+ 🔞

Давай разберём эту дичь, чтобы в голове не превратилось в кашу. Представь, что Statement — это просто папаша, а у него два сына, и оба — говнари, но со своими тараканами.

PreparedStatement — это такой занудный перфекционист. Его задача — выполнять обычные запросы типа «выбери, обнови, вставь, удали», но чтобы всё было безопасно и быстро. Он, блядь, параноик по поводу SQL-инъекций, поэтому заставляет тебя использовать вопросительные знаки ? вместо прямых значений. Зато потом один раз компилирует запрос и может его юзать с разными параметрами — умная жопа, что сказать.

Пример, чтобы не быть голословным:

String sql = "UPDATE users SET email = ? WHERE id = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, "new@email.com"); // Подставляем параметр по индексу, начиная с 1, а не с 0, запомни это, ёпта!
pstmt.setInt(2, 123);
int rowsUpdated = pstmt.executeUpdate(); // И поехали

А вот CallableStatement — это уже мажорный сынок, который работает только с хранимыми процедурами и функциями в самой базе. Типа, «зачем мне париться с логикой в коде, когда можно на стороне БД всё сделать?». Он умеет не только передавать параметры внутрь, но и вытаскивать результаты обратно через OUT-параметры. Хитрый, сука!

Смотри, как он выёбывается:

// Допустим, в базе есть процедура: get_user_name(IN user_id INT, OUT user_name VARCHAR)
String sql = "{call get_user_name(?, ?)}"; // Вот этот синтаксис с фигурными скобками — его фирменный приём
CallableStatement cstmt = connection.prepareCall(sql);
cstmt.setInt(1, 123); // Кидаем на вход айдишник
cstmt.registerOutParameter(2, Types.VARCHAR); // А вот это важно! Говорим драйверу: «Жди, ща тут имя пользователя вылезет»
cstmt.execute(); // Запускаем
String userName = cstmt.getString(2); // И вот, получаем наш OUT-параметр, красота!

Короче, резюмирую, чтобы ты не запутался:

Критерий PreparedStatement CallableStatement
Зачем нужен? Для безопасных SQL-запросов с параметрами Для вызова хранимых процедур/функций в БД
Параметры Только входные (IN) И входные (IN), и выходные (OUT), и те, что туда-сюда (INOUT)
Синтаксис "SELECT ... WHERE id = ?" "{call proc_name(?, ?)}" или "{? = call func_name(?)}"
Регистрация OUT Не, не надо Обязательно! registerOutParameter()

Вот и вся магия. Первый — для повседневной рутины, второй — когда нужно пообщаться с хранимой логикой базы. Главное — не перепутай, а то будет тебе волнение ебать, когда запрос не сработает.