Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Справочник Java

PreparedStatement

Заранее подготовленный SQL-запрос с параметрами ?. Защищает от SQL-инъекций.

Доступно с: Java 1.1

Синтаксис

public interface PreparedStatement extends Statement

Примеры

Вставка и выборка с параметрами. Номера параметров начинаются с 1:

import java.sql.*;
 
void main() throws SQLException {
    try (Connection conn = DriverManager.getConnection("jdbc:sqlite::memory:")) {
        try (Statement st = conn.createStatement()) {
            st.executeUpdate("CREATE TABLE users (name TEXT, age INTEGER)");
        }
 
        try (PreparedStatement insert = conn.prepareStatement(
                "INSERT INTO users (name, age) VALUES (?, ?)")) {
            insert.setString(1, "Anna");
            insert.setInt(2, 30);
            insert.executeUpdate();
            insert.setString(1, "Oleg");
            insert.setInt(2, 17);
            insert.executeUpdate();
        }
 
        try (PreparedStatement query = conn.prepareStatement(
                "SELECT name FROM users WHERE age >= ?")) {
            query.setInt(1, 18);
            try (ResultSet rs = query.executeQuery()) {
                while (rs.next()) {
                    IO.println(rs.getString("name"));
                }
            }
        }
    }
}

Результат:

Anna

Почему не склеивать строки: ввод пользователя меняет смысл запроса, а параметр — нет:

import java.sql.*;
 
void main() throws SQLException {
    try (Connection conn = DriverManager.getConnection("jdbc:sqlite::memory:");
         Statement st = conn.createStatement()) {
        st.executeUpdate("CREATE TABLE users (name TEXT, password TEXT)");
        st.executeUpdate("INSERT INTO users VALUES ('Anna', 'a1'), ('Oleg', 'o2')");
 
        String input = "x' OR '1'='1";
 
        String sql = "SELECT COUNT(*) FROM users WHERE password = '" + input + "'";
        try (ResultSet rs = st.executeQuery(sql)) {
            rs.next();
            IO.println("Concatenated: " + rs.getInt(1));
        }
 
        try (PreparedStatement ps = conn.prepareStatement(
                "SELECT COUNT(*) FROM users WHERE password = ?")) {
            ps.setString(1, input);
            try (ResultSet rs = ps.executeQuery()) {
                rs.next();
                IO.println("Parameter: " + rs.getInt(1));
            }
        }
    }
}

Результат:

Concatenated: 2
Parameter: 0

Пакетная вставка: addBatch() копит строки, executeBatch() отправляет их разом:

import java.sql.*;
 
void main() throws SQLException {
    try (Connection conn = DriverManager.getConnection("jdbc:sqlite::memory:")) {
        try (Statement st = conn.createStatement()) {
            st.executeUpdate("CREATE TABLE tags (name TEXT)");
        }
        try (PreparedStatement ps = conn.prepareStatement("INSERT INTO tags VALUES (?)")) {
            for (String tag : List.of("java", "sql", "jdbc")) {
                ps.setString(1, tag);
                ps.addBatch();
            }
            int[] counts = ps.executeBatch();
            IO.println(counts.length + " rows inserted");
        }
    }
}

Результат:

3 rows inserted

Примечания

Знак ? заменяет только значение — имя таблицы или столбца параметром передать нельзя. Значения задают методами setString(), setInt(), setLong(), setBigDecimal(), setObject(), а NULL — через setNull(index, Types.VARCHAR). executeUpdate() возвращает число изменённых строк, executeQuery() — ResultSet. Подготовленный запрос можно выполнять много раз с разными параметрами, база не разбирает SQL заново.

См. также

  • DriverManager.getConnection() — Открывает соединение с базой данных по JDBC-адресу.
  • ResultSet — Результат SELECT-запроса: курсор, который по одной перебирает строки таблицы.
  • Connection.setAutoCommit() — Включает или выключает автофиксацию. С false несколько запросов объединяются в транзакцию: commit() или rollback().

Вопросы и ответы по теме

В учебнике

  • Подготовленные запросы — PreparedStatement в JDBC — параметры ? в запросах, защита от SQL-инъекций, добавление, изменение и удаление строк через executeUpdate и получение сгенерированных ключей.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.