Руководство по JDBC v.1
Предыдущий | Содержание | Следующий
6 - PreparedStatement
6.1 Введение
ИнтерфейсPreparedStatement
наследует от Statement
и отличается
от последнего следующим:
- Экземпляры
PreparedStatement
"помнят" скомпилированные SQL-выражения. Именно поэтому они называются "prepared" ("подготовленные"). - SQL-выражения в
PreparedStatement
могут иметь один или более входной (IN) параметр. Входной параметр - это параметр, чье значение не указывается при создании SQL-выражения. Вместо него в выражении на месте каждого входного параметра ставится знак ("?"). Значение каждого вопросительного знака устанавливается методамиsetXXX
перед выполнением запроса.
PreparedStatement
прекомпилированны, исполнение этих запросов может
происходить несколько быстрее, чем в объектах Statement
. В
результате SQL-выражения, которые исполняются часто, в целях улучшения
производительности создают в виде объектов PreparedStatement
.
Оставаясь подклассом класса Statement
, класс
PreparedStatement
наследует все функции от Statement
.
В дополнении к ним он добавляет методы установки входных параметров. Кроме того,
три метода - execute
, executeQuery
и
executeUpdate
- модифицированы таким образом, что не имеют
аргументов. Старые методы класса Statement
(которые принимают
SQL-выражения в качестве едиственного аргумента) не должны использоваться в
объекте PreparedStatement
.
6.1.1 Создание объектов PreparedStatement
Следующий фрагмент кода, гдеcon
- это объект
Connection
, создает объект PreparedStatement
,
содержащий SQL-выражение с двумя параметрами:
PreparedStatement pstmt = con.prepareStatement( "UPDATE table4 SET m = ? WHERE x = ?");Объект
pstmt
отныне содержит выражение
"UPDATE table4 SET m = ? WHERE x = ?"
, которое уже отослано в СУБД
и подготовлено для выполнения.
6.1.2 Передача входных (IN) параметров
Перед выполнением объектаPreparedStatement
надо
установить значения всех его параметров. Это делается с помощью методов
setXXX
, где XXX
- это тип параметра. Например, если
параметр имеет Java-тип long
, используемый метод будет
setLong
. Первый аргумент методов setXXX
- это
порядковый номер параметра, а второй - значение, в которое надо его установить.
Например, следующий код устанавливает первый параметр в значение
123456789
, а второй - в 100000000
:
pstmt.setLong(1, 123456789); pstmt.setLong(2, 100000000);После установки параметра его можно использовать при многократном выполнении выражения до тех пор, пока он не очистится методом
clearParameters
.
В режиме соединения по умолчанию (разрешена автофиксация) каждый запрос фиксируется или откатывается автоматически.
Один и тот же объект PreparedStatement
может
выполняться много раз, если нижестоящий драйвер или СУБД будут сохранять
выражение (statement) в открытом состоянии даже после того как произойдет
фиксация. Иначе не имеет смысла пытаться улучшить производительность заменой
Statement
на PreparedStatement
.
Используя pstmt
из предыдущего примера,
следующий код устанавливает значения обоих параметров и выполняет
pstmt
10 раз. Как уже было отмечено, БД не должна закрывать
pstmt
. В этом примере первый параметр устанавливается в
"Hi"
и остается неизменным. Второй параметр устанавливается в
последовательные целые значения, начиная от 0 и заканчивая 9.
pstmt.setString(1, "Hi"); for (int i = 0; i < 10; i++) { pstmt.setInt(2, i); int rowCount = pstmt.executeUpdate(); }
6.1.3 Совместимость типов данных входных параметров
XXX
в начвании методов setXXX
- это
тип данных Java. Неявно он же является и типом данных JDBC (SQL), так как
драйвер отображает тип данных Java на соответствующий JDBC-тип (согласно таблице
из раздела 8.6.2)
перед отсылкой JDBC-типа в БД. Следующий код устанавливает второй параметр
объекта PreparedStatement
pstmt
в 44
с
типом данных short
:
Драйвер отошлет 44 в БД в виде типа JDBCpstmt.setShort(2, 44);
SMALLINT
, который является стандартным для Java-типа
short
.
На программисте лежит ответственность за совместимость
Java-типов входных параметров и ожидаемых базой данных соответствующих
JDBC-типов. Рассмотрим случай, когда ожидается SMALLINT
. Если
используется метод setByte
, то драйвер отошлет значение
TINYINT
в БД. Это, вероятно, работать будет, так как многие БД
преобразуют "похожие" типы данных друг в друга. Тем не менее, чтобы приложение
могдо работать как можно с большим количеством СУБД, лучше использовать
Java-типы, которые в точности соответствуют ожидаемым JDBC-типам. Если ожидается
JDBC-тип данных SMALLINT
, то использование именно
setShort
вместо setByte
сделает приложение более
переносимым.
6.1.4 Использование объектов
Программист может явно задать конвертирование входных параметров в определенный JDBC-тип с помощью методаsetObject
. Этот метод
может принимать третий аргумент, указывающий целевой JDBC-тип данных. Перед
отправкой в БД драйвер преобразует Object
в указанный JDBC-тип.
Если JDBC-тип не задан, то драйвер просто преобразует
Object
в его ближайший JDBC-эквивалент в соответствии с таблицей из
раздела 8.6.4,
а затем пошлет его в БД. Это подобно использованию обычных методов
setXXX
; в обоих случаях драйвер отображает Java-типы в JDBC-типы
данных перед отправкой значений в БД. Разница заключается в том, что если методы
setXXX
используют таблцу отображения Java-типов в JDBC-типы из
раздела 8.6.2),
то метод setObject
использует отображение из таблицы в разделе 8.6.4.
В случае использования метода setObject
тип
данных может быть неизвестен приложению на этапе его компиляции. Используя его,
приложение может подавать на вход значения любых типов данных и преобразовывать
их в ожидаемый базой данных JDBC-тип. Таблица из раздела 8.6.5
показывает все возможные преобразования, которые может проделать
setObject
.
6.1.5 Отсылка значений NULL в качестве входного параметра
МетодsetNull
позволяет отсылать
значения NULL
в БД как входные параметры. Хотя JDBC-тип параметра
все же можно задать явно.
JDBC-значение NULL
будет отослано в БД также в
том случае, если методу setXXX
будет передано Java-значение
null
(если метод принимает Java-объект в качестве аргумента). Тем
не менее, метод setObject
может принять значение null
только в случае, если задан JDBC-тип.
6.1.6 Отправка очень больших входных параметров
МетодыsetBytes
и setString
могут
отсылать неограниченное количество данных. Правда, иногда программисту легче
передавать большие значения в виде маленьких кусков. Это делается установкой
входного параметра в значение Java-потока ввода (input stream). Когда
выполняется выражение, JDBC-драйвер будет производить последовательные вызовы из
этого потока ввода, считывая его содержимое и пересылая его в виде значения
параметра.
JDBC предоставляет три метода установки входных параметров
в поток ввода: setBinaryStream
для потоков, содержащих обычные
байты, setAsciiStream
для потоков ASCII-символов и
setUnicodeStream
для потоков Unicode-символов. Эти методы, в
отличие от остальных методов setXXX
, принимают дополнительный
аргумент, равный количеству передаваемых в потоке байтов. Этот аргумент
необходим, так как некоторые СУБД требуют указания размера данных перед их
отсылкой.
Следующий код иллюстрирует отсылку файла в виде входного параметра запроса:
java.io.File file = new java.io.File("/tmp/data"); int fileLength = file.length(); java.io.InputStream fin = new java.io.FileInputStream(file); java.sql.PreparedStatement pstmt = con.prepareStatement( "UPDATE Table5 SET stuff = ? WHERE index = 4"); pstmt.setBinaryStream (1, fin, fileLength); pstmt.executeUpdate();При выполнении запроса для доставки данных последовательно считывается поток ввода
fin
.
Предыдущий | Содержание | Следующий