Ответ
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. Юзай его, и будет тебе счастье.