Statement и PreparedStatement

Базовый Java
≈ 2 мин чтения

Statement выполняет готовую строку SQL

Statement умеет отправить базе SQL, который уже полностью собран строкой. Для фиксированных служебных команд это возможно, но подставлять пользовательские значения через конкатенацию строк опасно и неудобно.

try (Statement statement = connection.createStatement()) {
    int updated = statement.executeUpdate(
            "UPDATE users SET active = false WHERE last_login IS NULL");
    System.out.println(updated);
}

executeUpdate() используют для команд, которые изменяют данные или схему и возвращают количество затронутых строк. Для запросов, возвращающих строки, применяется executeQuery().

PreparedStatement отделяет SQL от значений

Если в запросе есть данные, которые приходят из программы, обычно нужен PreparedStatement. В SQL ставятся маркеры ?, а значения передаются отдельными setter-методами. Нумерация параметров начинается с 1.

String sql = "SELECT id, name FROM users WHERE email = ?";

try (PreparedStatement statement = connection.prepareStatement(sql)) {
    statement.setString(1, email);

    try (ResultSet result = statement.executeQuery()) {
        while (result.next()) {
            System.out.println(result.getLong("id"));
        }
    }
}

Так значение email передаётся как данные, а не становится частью текста SQL. Это не только удобнее для типов и повторного выполнения, но и защищает от классической SQL-инъекции, которая возникает при небезопасной склейке пользовательского ввода с запросом.

Для параметризованных запросов предпочитай PreparedStatement. Не экранируй пользовательский ввод вручную и не собирай из него SQL конкатенацией строк, если значение можно передать через параметр.