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

Ответ

Statement и PreparedStatement — это два основных интерфейса для выполнения SQL в JDBC. PreparedStatement является расширением Statement и предпочтителен в большинстве случаев.

Statement — простой интерфейс для выполнения статических SQL-запросов.

  • Недостаток: Запрос формируется конкатенацией строк, что открывает уязвимость для SQL-инъекций.
  • Производительность: Каждый запрос компилируется в СУБД заново.

Пример (НЕБЕЗОПАСНЫЙ):

String userId = "123'; DROP TABLE users; --"; // Злонамеренный ввод
String sql = "SELECT * FROM users WHERE id = " + userId; // Инъекция возможна!
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql); // Выполнится DROP TABLE!

PreparedStatement — интерфейс для выполнения параметризованных SQL-запросов.

  • Безопасность: Параметры передаются отдельно от команды SQL, что исключает SQL-инъекции. СУБД рассматривает параметры как данные, а не как часть кода.
  • Производительность: Запрос прекомпилируется один раз и может выполняться многократно с разными параметрами, что эффективнее.
  • Читаемость: Код чище, особенно для запросов с множеством условий.

Пример (БЕЗОПАСНЫЙ):

String userId = "123'; DROP TABLE users; --"; // Тот же ввод
String sql = "SELECT * FROM users WHERE id = ?"; // Плейсхолдер '?'
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, userId); // Параметр безопасно подставляется
ResultSet rs = pstmt.executeQuery(); // Выполнится: SELECT * FROM users WHERE id = '123''; DROP TABLE users; --'
// Параметр экранирован, инъекция предотвращена. Запрос ищет пользователя с некорректным ID.
Сравнительная таблица: Критерий Statement PreparedStatement
Безопасность Уязвим к SQL-инъекциям Защищен от SQL-инъекций
Производительность Низкая (компиляция каждый раз) Высокая (прекомпиляция)
Использование Простые, одноразовые запросы Запросы с параметрами, многократное выполнение
Синтаксис Конкатенация строк Плейсхолдеры ? и методы setXxx()

Правило: Всегда используйте PreparedStatement для запросов, куда подставляются пользовательские данные.

Ответ 18+ 🔞

О, слушай, ну это ж классика, про которую каждый второй джуниор на собеседовании обоссывается! Statement и PreparedStatement, блядь. Ну, представь себе, что ты в баре заказываешь.

Statement — это как ты, мудак, каждый раз кричишь бармену новый заказ с нуля. «Дай пива!», потом «Дай пива и чипсов!», потом «Дай пива, чипсов и вот той тёлки телефон!». Каждый раз он тебя заново слушает, думает, хуярит стаканы. Медленно и, главное, опасно.

Смотри, какой пиздец может быть:

String userId = "123'; DROP TABLE users; --"; // Это тебе какой-то хитрожопый уебан в форму ввёл
String sql = "SELECT * FROM users WHERE id = " + userId; // И тут ты, долбоёб, склеиваешь строку
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql); // И поехали! База выполняет: SELECT... а потом БАХ! DROP TABLE users! Всё, пиздец, таблицы нет!

Вот это и есть SQL-инъекция, когда через дыру в твоём говнокоде можно всю базу разъебать. Statement её просто обожает, как сосалка.

А теперь PreparedStatement — это твой личный, прекомпилированный, заученный заказ. Ты один раз бармену сказал: «Брат, запомни: мне всегда вот это (?) и вот это (?)». А потом просто киваешь: «Давай первое — пиво, второе — чипсы». И он уже знает схему, просто подставляет значения. Быстро и, что главное, безопасно.

Смотри, как красота:

String userId = "123'; DROP TABLE users; --"; // Тот же самый уебанский ввод
String sql = "SELECT * FROM users WHERE id = ?"; // А тут стоит плейсхолдер, знак вопроса. Это как заглушка.
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, userId); // Сюда ты безопасно засовываешь значение. База видит его КАК ДАННЫЕ, а не как команду.
ResultSet rs = pstmt.executeQuery(); // И выполнится ебаный запрос: SELECT * FROM users WHERE id = '123''; DROP TABLE users; --'

Видишь? Вся эта инъекционная хуйня ушла в кавычки и стала просто ебанутым значением для поиска. База будет искать пользователя с идиотским ID 123'; DROP TABLE users; -- и, конечно, не найдёт. А таблица users останется на месте, целая и невредимая. Ёпта, вот это магия!

Короче, сводка для тех, кто в танке:

Критерий Statement (говно) PreparedStatement (огонь)
Безопасность Уязвим, как голый мужик в метро зимой. SQL-инъекции его ебут в сраку. Защищён. Параметры — это данные, а не код. Хуй кто проинжектит.
Скорость Тупой и медленный. Каждый запрос компилирует заново, как будто впервые видит. Быстрый и умный. Скомпилировал схему раз — юзай на разные значения.
Когда юзать Ну, наверное, никогда. Разве что для каких-нибудь разовых скриптов, где параметров нет от слова совсем. ВСЕГДА, блядь! Особенно когда в запрос идут данные от пользователя, из формы, из файла — откуда угодно.

Итог, ёбта: если ты не хочешь однажды проснуться с ебучей базой, где вместо пользователей зияет пустота, забудь про Statement для динамических запросов. PreparedStatement — твой бронежилет, твой презерватив и твой лучший друг в мире JDBC. Юзай его, и будет тебе счастье.