Работа с PreparedStatement
Самый простой интерфейс Statement мы уже видели. И хотя он вполне пригоден для работы, для сложных запросов он подходит не так хорошо. В некоторых источниках высказывается мнение, что использовать Statement вообще не надо — вместо него подходят более сложные и более функционально насыщенные интерфейсы.
Возникает вполне резонный вопрос — а зачем эти интерфейсы нужны? Давай разбираться.
Для начала мы рассмотрим интерфейс PreparedStatement и другие возможности JDBC. К интерфейсу CallableStatement обратимся позже — его использование, во-первых, не так часто встречается, а во-вторых — после всего рассмотренного про него разговор уже можно делать достаточно коротким.
Кроме того, PreparedStatement отлично помогает от популярного подхода к взлому базы данных, который называется SQL Injection.
Но подробнее об этом немного позднее.
PreparedStatement
Если попытаться перевести название PreparedStatement , то можно получить что-то вроде “подготовленный оператор”. Самым важным здесь является слово “подготовленный”. В чем заключается “подготовленность”?
Прежде чем мы рассмотрим этот вопрос, предлагаю увидеть достаточно важный с точки зрения удобства момент, который возникает очень часто. Итак, в каком-либо приложении нам надо вставить данные о контакте в таблицу CONTACT. Для этого нам надо подготовить запрос наподобие такого:
INSERT INTO JC_CONTACT (FIRST_NAME, LAST_NAME, PHONE, EMAIL) VALUES (‘Harry’,'Potter','+79112345678','harry@example.com);
На первый взгляд кажется, что все не так уж сложно и страшно. Надо написать код, который будет собирать нужную нам строку из параметров: имя, фамилия, адрес и телефон. Надо только не забыть, что все строковые данные надо окружить символом ординарная кавычка.
Если мы это делаем в отдельной функции, то получается что-то такое:
public String buildInsert(String firstName,, String lastName, String phone, String email)
Мы передаем в функцию параметров имя, фамилию, телефон и адрес в виде, и из них составляем строку SQL-запроса. Кавычки немного портят картину, но пока не страшно.
Ок, а что делать с числами? Их не надо окружать кавычками. Опаньки, в одном случае надо кавычки, в другом — не надо. Ситуация усложняется.
Теперь добавим еще одну проблему — а если внутри строки есть ординарная кавычка (и даже не одна)? Надо предварительно искать такие кавычки и обрабатывать их. Мдааа. Как-то неуютно начинаем себя ощущать.
Если теперь прибавить обработку дат, то задача становится совсем скучной — надо делать огромное количество работы. С датами вообще неприятно — разные SQL-сервера принимают для дат разные форматы.
Итак, что мы видим? Если нам надо использовать параметры внутри запроса, то в ручном режиме построение запроса становится очень неприятным делом. Причем не просто неприятным — я бы даже сказал занудным. Надо учитывать огромное количество случаев, и это ужасно скучная работа. В основном именно для таких случаев и был предложен интерфейс PreparedStatement .
Этот запрос позволяет вам сделать две вещи:
- Заранее подготовить запрос с указанием мест, где будут подставляться параметры
- Установить параметры определенного типа и выполнить после этого запрос с уже установленными параметрами
Пример использования PreparedStatement
Конструкция для PreparedStatement для нашего варианта установки параметров будет выглядеть вот так:
// Переменные для примера String firstName = "Harry"; String lastName = "Potter"; String phone = "+12871112233"; String email = "harry@example.com"; // Запрос с указанием мест для параметров в виде знака "?" String sql = "INSERT INTO JC_CONTACT (FIRST_NAME, LAST_NAME, PHONE, EMAIL) VALUES (?, ?, ?, ?)"; // Создание запроса. Переменная con — это объект типа Connection PreparedStatement stmt = con.prepareStatement(sql); // Установка параметров stmt.setString(1, firstName); stmt.setString(2, lastName); stmt.setString(3, phone); stmt.setString(4, email); // Выполнение запроса stmt.executeUpdate();
Как видишь, все достаточно несложно.
Во-первых, при написании SQL-запроса на места, куда надо будет подставлять параметры, записываются знаки вопроса — “?”.
Во-вторых — запрос создается через вызов con.prepareStatement() .
В-третьих — установка параметров идет через указание номера и значения. Обрати внимание, что номер параметров начинаются с 1, а не с 0, как мы привыкли при работе с массивами и коллекциями.
Интерфейс PreparedStatement содержит методы для установки строк — setString() , для установки чисел — setInt() , setLong() , setDouble() , для установки дат — setDate() . И более сложных типов — это можно увидеть в документации.
В-четвертых — вызов stmt.executeUpdate() выполняется уже без указания строки запроса.
Крайне настоятельно рекомендую подружиться с PreparedStatement — это очень эффективный инструмент.