| 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 (набор данных)".