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 и получение сгенерированных ключей.