Ответ
Оба интерфейса наследуются от 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() |
Вот и вся магия. Первый — для повседневной рутины, второй — когда нужно пообщаться с хранимой логикой базы. Главное — не перепутай, а то будет тебе волнение ебать, когда запрос не сработает.