В чем разница между prepared statement и обычным statement в Java
Что проверяют
Знаете ли вы, как JDBC передаёт параметры в базу и почему это закрывает SQL-инъекции, а не просто делает код аккуратнее. Следом часто спрашивают, как подставить в запрос имя колонки или список для IN, и правда ли PreparedStatement всегда быстрее.
Как отвечать
Statement: выполняет строку SQL как есть. Если вы склеили её с пользовательским вводом, ввод становится частью запроса, отсюда инъекции. Годится для статического SQL и DDL;PreparedStatement: наследникStatement, запрос с плейсхолдерами?, значения задаются черезsetString,setLong,setObject,setNull. Значение передаётся как данные и не может поменять структуру запроса;- повторное выполнение: один объект выполняется много раз с разными параметрами, а
addBatch()иexecuteBatch()дают пакетную вставку за одну отправку; CallableStatement: наследникPreparedStatementдля хранимых процедур.
Про производительность отвечайте аккуратно: выгода зависит от драйвера. Драйвер PostgreSQL переходит на серверный подготовленный запрос не сразу, а после нескольких выполнений (параметр prepareThreshold). MySQL Connector/J по умолчанию вообще эмулирует подготовку на клиенте, пока не включить useServerPrepStmts. Поэтому главный аргумент это безопасность и корректная передача типов (даты, null, спецсимволы в строках), а скорость идёт бонусом при повторных вызовах.
Добавьте, что JdbcTemplate, JPA и Hibernate под капотом работают через PreparedStatement, и что Connection, PreparedStatement и ResultSet закрываются через try-with-resources.
Где спотыкаются
Пытаются передать через ? имя таблицы, колонки или направление ORDER BY. Плейсхолдер принимает только значения, для идентификаторов нужен белый список допустимых вариантов.
Склеивают строку с вводом, а потом передают её в prepareStatement. Защиты при этом нет никакой, инъекция уже внутри текста запроса.
Не знают, как сделать IN со списком: нужно сгенерировать нужное число ? или, в PostgreSQL, написать = ANY(?) и передать массив через setArray.