Contents | Prev | Next | JDBCTM Guide: Getting Started |
CallableStatement
предоставляет унифицированный способ вызова хранимых процедур в любой СУБД.
Вызов процедуры осуществляется с помощью escape-синтаксиса в одной из двух форм:
с результирующим параметром и без него. (См. раздел 4, "Запрос
(Statement)" об escape-синтаксисе). Результирующий параметр - это один из типов
выходных (OUT) параметров, являющийся возвращаемым значением хранимой процедуры.
Обе формы могут иметь переменное число аргументов на входе (параметры IN),
выходе (параметры OUT) или входных и выходных параметров одновременно
(INOUT-параметры). Вопросительный знак означает местоположение параметра.
Синтаксис вызова хранимой процедуры в JDBC показан ниже. Квадратные скобки означают, что то, что находится между ними, необязательно, и сами по себе не являются частью синтаксиса.
{call имя_процедуры[(?, ?, ...)]}Синтаксис для процедуры, возвращающей результат:
{? = call имя_процедуры[(?, ?, ...)]}Синтаксис хранимой процедуры без параметров:
{call имя_процедуры}Обычно тот, кто использует объект
CallableStatement
, уже знает, что используемая СУБД поддерживает
хранимые процедуры и какие именно процедуры имеются в БД. Тем не менее, чтобы
это выяснить, достаточно вызвать некоторые методы объекта
DatabaseMetaData
. Например, метод
supportsStoredProcedures
возвращает true
, если СУБД
поддерживает хранимые процедуры, а метод getProcedures
возвращает
описания доступных процедур.
CallableStatement
наследует методы
Statement
общей для обработки SQL-запросов, а также методы
PreparedStatement
для обработки входных (IN) параметров. Все
методы, объявленные в CallableStatement
обрабатывают выходные (OUT)
параметры следующим образом: указание JDBC-типов данных (т.е. SQL-типов)
выходных параметров, извлечение из них значений или проверка их на
NULL
.
CallableStatement
создаются методом
prepareCall
объекта Connection
. Приведем пример,
который создает экземпляр CallableStatement
, содержащий вызов
хранимой процедуры getTestData
с двумя аргументами и без
возвращаемого параметра:
CallableStatement cstmt = con.prepareCall( "{call getTestData(?, ?)}");Какими именно параметрами (IN, OUT или INOUT) являются знаки вопроса - зависит от самой хранимой процедуры
getTestData
.
CallableStatement
осуществляется
с помощью методов setXXX
, унаследованных от
PreparedStatement
. Типы передаваемых значений определяются тем,
какой из методов setXXX
используется (setFloat
для
передачи значений float
и т.п.).
JDBC-типы всех OUT-параметров хранимых процедур должны
быть зарегистрирваны перед их вызовом. Это необходимо, так как некоторым СУБД
нужно передавать информацию и типах данных. Регистрация типов данных выходного
параметра производится методом registerOutParameter
. Только в этом
случае после выполнения запроса методы getXXX
класса
CallableStatement
смогут получить значения параметров. Необходимо
использовать подходящий по типу данных Java метод getXXX
в
соответствии с зарегистрированным JDBC-типом параметра. (Стандартное отображение
типов из JDBC в Java показано в таблице раздела 8.6.1.)
Другими словами, registerOutParameter
использует JDBC-тип (тот,
который подходит к JDBC-типу возвращаемого из БД значения), а
getXXX
преобразует его в тип Java.
Приведем пример регистрации выходных параметров,
выполнения хранимой процедуры cstmt
и считывание выходных
параметров. Метод getByte
извлекает байт из первого выходного
параметра, а getBigDecimal
возвращает объект
BigDecimal
(с тремя цифрами после десятичной точки) из второго:
CallableStatement cstmt = con.prepareCall( "{call getTestData(?, ?)}"); cstmt.registerOutParameter(1, java.sql.Types.TINYINT); cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 3); cstmt.executeQuery(); byte x = cstmt.getByte(1); java.math.BigDecimal n = cstmt.getBigDecimal(2, 3);В отличие от
ResultSet
,
CallableStatement
не может считывать большие значения
последовательно (в потоке).
setXXX
(унаследованный от PreparedStatement
), так и метод
registerOutParameter
. Метод setXXX
устанавливает
входное значение параметра, а registerOutParameter
регистрирует тип
выходного значения.
Типы входного и выходного значений, зарегистрированных
методом registerOutParameter
, должны быть одинаковыми. Для чтения
выходного значения используется соответствующий метод getXXX
.
Например, для параметра типа byte нужно использовать метод установки значения
setByte
, передавать JDBC-тип данных TINYINT
методу
registerOutParameter
и использовать getByte
для чтения
выходного значения. (В разделе 8
"Отображение типов JDBC на типы Java" приведена более подробная информация о
соответствии типов данных).
В следующем примере вызывается хранимая процедура
reviseTotal
с единственным INOUT-параметром. Метод
setByte
устанавливает значение параметра в 25
, которое
будет представлено базе данных как TINYINT
. Далее метод
registerOutParameter
регистрирует параметр как
TINYINT
. После выполнения хранимой процедуры возвращается значение
типа TINYINT
, которое будет считано методом getByte
в
виде типа byte
языка Java.
CallableStatement cstmt = con.prepareCall( "{call reviseTotal(?)}"); cstmt.setByte(1, 25); cstmt.registerOutParameter(1, java.sql.Types.TINYINT); cstmt.executeUpdate(); byte x = cstmt.getByte(1);
CallableStatement
, а затем выходные (OUT) параметры.
Если объект CallableStatement
возвращает
несколько объектов ResultSet
(с использованием метода
execute
), то ВСЕ результаты должны быть прочитаны перед первым
обращением к выходным параметрам. В этом случае для того, чтобы прочитать все
результаты, надо последовательно вызывать методы Statement
getResultSet
, getUpdateCount
и
getMoreResults
до тех пор, пока не останется больше результатов.
После этого значения выходных параметров могут быть извлечены спомощью
методов CallableStatement.getXXX
.
NULL
. При этом методы getXXX возвращают null
,
0
или false
, в зависимости от типа данных. Как и в
случае с ResultSet
, единственным способом узнать, вернула ли
процедура 0
, false
или NULL
, является
вызов метода wasNull
, который возвращает true
, если
последнее значение, считанное одним из методов getXXX
был
NULL
, и false
иначе. См. раздел 5,
"ResultSet (набор данных)".