Что такое Statement в JDBC и когда его используют?

Ответ

Statement — это базовый интерфейс JDBC для выполнения статических SQL-запросов без параметров. Он создается из объекта Connection.

Основное использование и пример:

Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
Statement stmt = conn.createStatement();

// Для SELECT используем executeQuery()
String sqlQuery = "SELECT id, name FROM users WHERE status = 'active'";
ResultSet rs = stmt.executeQuery(sqlQuery);
while (rs.next()) {
    System.out.println(rs.getInt("id") + ": " + rs.getString("name"));
}

// Для INSERT, UPDATE, DELETE используем executeUpdate()
String sqlUpdate = "UPDATE users SET status = 'inactive' WHERE last_login < '2023-01-01'";
int rowsAffected = stmt.executeUpdate(sqlUpdate);
System.out.println("Обновлено строк: " + rowsAffected);

// Всегда закрываем ресурсы!
rs.close();
stmt.close();
conn.close();

Критические недостатки и почему его избегают:

  1. Уязвимость к SQL-инъекциям: Запрос формируется конкатенацией строк, что позволяет злоумышленнику внедрить恶意 SQL-код.
    // ОПАСНО!
    String userInput = "'; DROP TABLE users; --";
    String sql = "SELECT * FROM users WHERE name = '" + userInput + "'";
    stmt.executeQuery(sql); // Выполнит DROP TABLE!
  2. Низкая производительность: Каждый запрос компилируется в СУБД заново, кеширование планов запросов неэффективно.

Когда использовать (редкие случаи):

  • Выполнение DDL-операций (CREATE, ALTER, DROP).
  • Выполнение простых, статистических запросов, где параметры известны на этапе компиляции и полностью контролируются разработчиком.

Рекомендация: Для любых запросов с данными, полученными от пользователя или извне, всегда используйте PreparedStatement, который защищает от инъекций и повышает производительность.

Ответ 18+ 🔞

Да ты посмотри, что за зверь такой — этот Statement! Ну, базовый интерфейс в JDBC, чтобы тупо, в лоб, SQL-запросы гонять. Без параметров, без ничего. Рождается он прямиком из Connection, как гриб после дождя.

Вот как его, голодранца, используют:

Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
Statement stmt = conn.createStatement();

// Для SELECT — executeQuery()
String sqlQuery = "SELECT id, name FROM users WHERE status = 'active'";
ResultSet rs = stmt.executeQuery(sqlQuery);
while (rs.next()) {
    System.out.println(rs.getInt("id") + ": " + rs.getString("name"));
}

// Для INSERT, UPDATE, DELETE — executeUpdate()
String sqlUpdate = "UPDATE users SET status = 'inactive' WHERE last_login < '2023-01-01'";
int rowsAffected = stmt.executeUpdate(sqlUpdate);
System.out.println("Обновлено строк: " + rowsAffected);

// И не забудь всё прибить, а то память жрать будет!
rs.close();
stmt.close();
conn.close();

А теперь, блядь, главная причина, почему на него смотрят как на прокажённого:

  1. Уязвимость к SQL-инъекциям — это просто пиздец! Запрос склеивается из строк, как попало. Любой школьник с полпинка тебе всю базу угробит.
    // ЭТО ПРЯМАЯ ДОРОГА В АД, НАХУЙ!
    String userInput = "'; DROP TABLE users; --";
    String sql = "SELECT * FROM users WHERE name = '" + userInput + "'";
    stmt.executeQuery(sql); // Ёбта, и таблицы users как не бывало!
  2. Производительность — ниже плинтуса. Каждый раз, сука, запрос компилируется в СУБД с нуля. Планы выполнения не кешируются нормально, всё впустую.

Так когда же его, этого убогого, хоть куда-то можно пристроить?

  • Ну, для DDL-команд — CREATE, ALTER, DROP. Там параметров обычно нет.
  • Для каких-нибудь своих, внутренних, статических запросов, где все данные известны заранее и под контролем. Но это редкость, блядь.

Итог, как отче наш: Для любых запросов, куда попадают данные от пользователя или из внешнего мира — в рот меня чих-пых, забудь про Statement! Бери PreparedStatement. Он и от инъекций спасёт, и быстрее работать будет. Не будь мудаком, как тот Герасим, который всё по-своему, через жопу.