Работа с Базой Данных | |||||||||||||||||||||
Взаимодействие с Реляционной Базой Данных | |||||||||||||||||||||
Сервис LiveWire Database Service даёт возможность взаимодействовать с
реляционной БД различными способами.
|
|||||||||||||||||||||
Автоматическое Отображение Результатов Выполнения Запроса | |||||||||||||||||||||
Наиболее простым и быстрым способом отобразить результаты выполнения
запросов к БД является использование метода SQLTable объекта database
или объекта Connection. Метод SQLTable принимает оператор SQL SELECT и
возвращает HTML-таблицу. Каждый ряд и столбец в запросе это ряд и столбец
таблицы. Таблица HTML имеет также заголовочную ячейку для каждого столбца
таблицы БД. В качестве примера: если myconn это Connection -объект, следующий оператор JavaScript отображает результат выполнения запроса к БД в виде таблицы: myconn.SQLTable("select * from videos"); Вот первая часть таблицы, которая могла бы быть сгенерирована этим оператором:
|
|||||||||||||||||||||
Выполнение Произвольных Операторов SQL | |||||||||||||||||||||
Метод execute объекта database или объекта Connection даёт приложению возможность выполнять произвольный оператор SQL. Использование execute называется выполнением передаваемого SQL, поскольку этот метод передаёт SQL непосредственно на сервер. Вы можете использовать execute для выполнения оператора SQL любого языка определения данных/data definition language (DDL) или языка манипулирования данными/data manipulation language (DML), поддерживаемого сервером БД. Примером могут служить операторы CREATE, ALTER и DROP. Хотя Вы можете использовать execute для выполнения любого оператора SQL, Вы не можете с помощью этого метода возвращать данные. Обратите внимание, что execute служит для выполнения стандартных операторов SQL, а не для выполнения расширений SQL, поставляемых некоторыми производителями БД. Например, Вы не можете вызвать функцию Oracle describe или функцию Informix load из метода execute. Для выполнения передаваемых операторов SQL просто задайте оператор SQL как параметр метода execute. Например, Вам нужно удалить таблицу из БД, на которую имеется ссылка в свойстве oldtable объекта project. Чтобы выполнить это, Вы можете использовать такой вызов метода: connobj.execute("DROP TABLE " + project.oldtable); При использовании execute Ваш SQL-оператор обязан строго соответствовать требованиям синтаксиса SQL данного сервера БД. Например, некоторые серверы требуют, чтобы каждый оператор SQL заканчивался символом "точка с запятой". Дополнительно см. документацию к Вашему серверу БД. Если Вы не стартуете транзакцию явно, единственный оператор подтверждается автоматически. Для выполнения некоторых операций, таких как создание и удаление таблиц, Вам могут понадобиться права доступа, предоставляемые администратором базы данных. См. документацию Вашего сервера БД и обратитесь к администратору сервера БД. |
|||||||||||||||||||||
Манипуляции с Результатами Выполнения Запросов с Помощью Курсоров | |||||||||||||||||||||
Часто Вам необходимо не просто отобразить таблицу с результатами выполнения запроса, но изменить форматирование этих результатов или даже выполнить какую-нибудь их обработку. Для манипуляций результатами выполнения запроса Вы работаете с курсором БД, возвращаемым запросом к БД. Для создания экземпляра класса Cursor вызовите метод cursor объекта database или объекта Connection, передав ему оператор SQL SELECT в качестве параметра. Вы можете представить курсор как виртуальную таблицу с рядами и столбцами, специфицированный по запросу. Курсор предполагает также понятие текущего ряда, который в реальности является указателем на ряд виртуальной таблицы. Когда Вы выполняете операции с курсором, они обычно воздействуют на текущий ряд. По окончании работы, закройте курсор БД путём вызова его метода close. Соединение с БД не может быть освобождено, пока не закрыты все ассоциированные с ним курсоры. Например, если Вы вызываете метод release объекта Connection и это соединение имеет ассоциированный курсор, который не был закрыт, соединение не будет освобождено, пока курсор не будет закрыт. В таблице обобщены методы и свойства класса Cursor.
|
|||||||||||||||||||||
Создание Курсора | |||||||||||||||||||||
Как только приложение установило соединение с БД, Вы можете создать курсор путём вызова метода cursor ассоциированного объекта database или Connection. Создание объекта Cursor также открывает курсор в БД. Вам не нужно выполнять отдельную команду open. Можно предоставить следующую информацию при создании объекта Cursor:
Например, следующий оператор создаёт курсор для записей таблицы CUSTOMER. Записи содержат столбцы id, name и city и упорядочены по значениям столбца id. custs = connobj.cursor ("select id, name, city Этот оператор устанавливает в переменную custs объект Cursor. Запрос SQL может вернуть следующие ряды: 1 Sally Smith Suva Затем Вы можете получить доступ к этой информации через использование методов Cursor-объекта custs. Этот объект имеет свойства id, name и city, соответствующие столбцам виртуальной таблицы. Когда Вы первоначально создаёте Cursor-объект, указатель позиционируется сразу перед первым рядом виртуальной таблицы. В последующих разделах рассматривается, как получить информацию из виртуальной таблицы. Вы можете также использовать оператор конкатенации строк (+) и строковые переменные (такие как значения свойств client или request) при конструировании оператора SELECT. Например, следующий вызов использует ранее сохранённый customer ID для последующей специализации запроса: custs = connobj.cursor ("select * from customer where id = " + client.customerID); При попытке создания Cursor-объекта Вы можете столкнуться с различными проблемами. Например, если оператор SELECT в вызове метода cursor обращается к несуществующей таблице, БД возвращает ошибку, и метод cursor возвращает null вместо Cursor-объекта. В этой ситуации Вы должны использовать методы majorErrorCode и majorErrorMessage для определения возникшей ошибки. В качестве второго примера, предположим, что оператор SELECT обращается к существующей таблице, в которой нет рядов. В этом случае БД может не возвратить ошибку, а метод cursor возвратит верный Cursor -объект. Однако, поскольку этот объект не содержит рядов, при первой попытке использования метода next в этом объекте он возвратит false. Ваше приложение должно проверять возможность возникновения такой ситуации. Когда Вы создаёте курсор, он получает свойство colName для каждого именованного столбца виртуальной таблицы (отличное от свойств, соответствующих агрегатным функциям), как определено оператором SELECT. Вы можете получать доступ к значениям текущего ряда, используя эти свойства. В вышеприведённом примере курсор имеет свойства для столбцов id, name и city. Вы можете вывести значения для первого возвращённого ряда, используя следующие операторы: // Создаётся Cursor-объект. Сначала текущим рядом является первый ряд таблицы. Выполнение метода next передвигает текущий ряд на первый ряд таблицы. Например, предположим, что это первый ряд курсора: 1 Sally Smith Suva Вы можете обращаться к свойствам Cursor -объекта (или, в действительности, объекта JavaScript) как к элементам массива. Элемент массива с индексом [0] соответствует первому столбцу, элемент массива с индексом [1] соответствует второму столбцу, и так далее. Например, Вы можете использовать индекс для отображения тех же значений столбцов, что и в предыдущем примере: write ("<B>Customer Name:</B> " +
custs[1] + "<BR>"); Эта техника особенно применима внутри циклов. Например, Вы можете создать Cursor -объект с названием custs и вывести результат выполнения запроса в виде таблицы HTML с помощью следующего кода: // Создаётся Cursor-объект. Этот код может вывести примерно такую таблицу:
Отображение Выражений и Агрегатных Функций Операторы SELECT могут запрашивать значения, не являющиеся столбцами в БД, такие как агрегатные значения и выражения SQL. Для таких значений Cursor -объект не имеет именованного свойства. Вы можете получить к ним доступ только через использование свойства индекса массива Cursor -объекта для данного значения. В следующем примере создаётся курсор с именем empData, делается переход к первому ряду этого курсора и затем отображается значение, запрошенное агрегатной функцией MAX. Выполняется также проверка того, что результаты из БД верны, перед тем как использовать их: empData = connobj.cursor ("select min(salary), avg(salary), Во втором примере создаётся курсор с именем empRows для подсчёта количества рядов в таблице, выполняется переход к ряду в этом курсоре, а затем отображается количество рядов параллельно с выполнением проверки на верность данных: empRows = connobj.cursor ("select count(*) from employees"); Сначала указатель курсора позиционируется перед первым рядом виртуальной таблицы. Метод next используется для перемещения между записями виртуальной таблицы. Этот метод передвигает указатель на следующий ряд и возвращает true, когда следующий ряд виртуальной таблицы найден. Если следующего ряда нет, next возвращает false. Например, предположим, что виртуальная таблица имеет столбцы с названиями title, rentalDate и dueDate. Следующий код использует next для итерации по рядам и отображения значений столбцов в таблице: // Создаём курсор. Этот код даст на выходе:
Вы не всегда можете находиться в нужном месте в курсоре. Например, предположим, что Вы создаёте курсор и, пока Вы работаете с ним, кто-то добавляет ряд в таблицу. В зависимости от установок БД, этот ряд может появиться в Вашем курсоре. Исходя из этого, когда это удобно (как при обновлении рядов), Вы можете сделать так, чтобы Ваш код проверял, находится ли указатель в нужном ряду. Метод columns класса Cursor возвращает количество столбцов в курсоре. Этот метод не принимает параметров: custs.columns() Вы можете использовать этот метод, если нужно итерировать по каждому столбцу курсора. Метод columnName класса Cursor возвращает имя столбца виртуальной таблицы. Этот метод принимает параметр - целое число, специфицирующее порядковый номер столбца, начиная с 0. Первым столбцом виртуальной таблицы является столбец 0, вторым - столбец 1, и так далее. Например, следующее выражение присваивает имя первого столбца курсора custs переменной header: header = custs.columnName(0) Если Ваш оператор SELECT использует шаблон (*) для выбора всех столбцов таблицы, метод columnName не гарантирует, что порядок присвоения номеров столбцам будет тем же. То есть, предположим, у Вас есть оператор: custs = connobj.cursor ("select * from customer"); Если таблица customer имеет 3 столбца, ID, NAME и CITY, Вы не сможете заранее предугадать, который из этих столбцов будет custs.columnName(0). (Конечно, есть гарантия, что последовательные вызовы columnName дадут аналогичный результат). Если порядок для Вас важен, можно жёстко кодировать имена в операторе выборки, как здесь: custs = connobj.cursor ("select ID, NAME, CITY from customer"); В этом операторе, custs.columnName(0) это ID, custs.columnName(1) это NAME, а custs.columnName(2) это CITY. Изменение Информации Базы Данных Вы можете использовать обновляемый курсор для модифицирования таблицы на основе текущего ряда курсора. Чтобы запросить обновляемый курсор, добавьте дополнительный параметр true при создании курсора, как в этом примере: custs = connobj.cursor ("select id, name, city from customer", true) Чтобы курсор был обновляемым, оператор SELECT обязан быть обновляемым запросом (запросом, позволяющим производить обновление). Например, оператор не может запрашивать ряды из более чем одной таблицы или содержать условие GROUP BY, а также обычно он обязан запрашивать ключевые значения таблицы. Дополнительно о конструировании обновляемых запросов см. документацию производителя БД. Когда курсоры используются для внесения изменений в Вашу БД, Вы всегда должны работать в рамках явной транзакции. Вы делаете это через использование методов beginTransaction, commitTransaction и rollbackTransaction Если в таких ситуациях Вы не используете явные транзакции, Вы можете получать ошибки из Вашей БД. Например, Informix и Oracle возвращают сообщения об ошибке, если Вы используете курсор без явной транзакции. Oracle возвращает Error ORA-01002: fetch out of sequence; Informix возвращает Error -206: There is no current row for UPDATE/DELETE cursor. Вы не обязательно привязаны к позиции в курсоре. Исходя из этого, при внесении изменений в БД не забывайте проверять, в каком ряду Вы работаете, прежде чем изменять его. Также запомните, что при создании курсора указатель позиционируется перед рядом курсора. Так, чтобы обновить ряд, Вы обязаны вызвать метод next как минимум один раз для установки указателя на первый ряд таблицы. После этого Вы можете присваивать значения столбцам курсора. В следующем примере обновляемый курсор вычисляет премию для продавцов, выполнивших норму. Затем этой информацией обновляется БД: connobj.beginTransaction (); Этот пример создаёт обновляемый курсор для всех employees/служащих департамента Sales. Производится итерация по рядам курсора через использование определяемой пользователем функции JavaScript metQuota, для того чтобы определить, выполнил ли служащий норму. Эта функция использует значение свойства quota объекта request (возможно, установленное в форме на клиентской странице) и столбец sold курсора для выполнения этого определения. Код затем устанавливает соответствующую премию и вызывает updateRow для модифицирования таблицы employees. Когда пройдены все ряды курсора, подтверждается транзакция. Если вызов метода cursor не вернул никакого курсора, транзакция откатывается. Помимо метода updateRow, Вы можете использовать методы insertRow и deleteRow для вставки нового ряда или удаления текущего. При использовании deleteRow не нужно присваивать никакого значения, поскольку этот метод просто удаляет весь ряд. Если Вы используете insertRow, значения, присваиваемые столбцам, используются для нового ряда. Если перед этим Вы вызвали метод next курсора, то текущие значения в ряду используются для столбцов без присвоенных значений; иначе столбцы будут иметь значения null. Также, если некоторые столбцы таблицы не вошли в курсор, insertRow вставляет null в эти столбцы. Место расположения вставляемого ряда зависит от библиотеки производителя БД. Если Вам нужен доступ к ряду после вызова метода insertRow, Вы обязаны сначала закрыть имеющийся курсор, а затем открыть новый. В DB2 имеется тип данных Time. JavaScript не имеет соответствующего типа данных. Поэтому Вы не можете обновлять ряды значениями, использующими тип данных DB2 Time. |
|||||||||||||||||||||
Обслуживание Транзакций | |||||||||||||||||||||
Транзакция это несколько действий с базой данных, выполняемых вместе. Либо все эти действия выполняются успешно, либо все вместе терпят неудачу. Если эти действия выполняют (окончательно) изменения БД, говорится, что транзакция подтверждена. Вы можете также выполнить откат /roll back транзакции, т.е. не подтвердить её; это отменяет все выполненные действия. Транзакции важны для поддержания целостности и структуры данных. В то время как различные серверы БД реализуют механизм транзакций с некоторыми отличиями, сервис LiveWire Database Service предоставляет одни и те же методы для обслуживания транзакций на всех БД. Проверьте в документации продавца БД информацию о согласованности данных и уровнях изоляции транзакций. Вы можете использовать явный контроль транзакции над выполнением любого набора действий. Например, акции, модифицирующие БД, должны проходить под управлением транзакций. Это акции, соответствующие операторам SQL INSERT, UPDATE и DELETE. Транзакции могут также использоваться для контролирования согласованности данных. Для большинства БД, если Вы не выполняете явного управления транзакциями, машина выполнения использует фоновый механизм БД - autocommit/автоподтверждение, когда каждый оператор в БД рассматривается как отдельная транзакция. Каждый оператор подтверждается или откатывается немедленно на основе успеха или неуспеха выполнения каждого отдельного оператора. Явное управление транзакциями переопределяет работу этого механизма по умолчанию. В некоторых БД, таких как Oracle, autocommit это явный механизм, который LiveWire включает для каждого отдельного оператора. В других БД, таких как Informix, autocommit это поведение по умолчанию, если Вы не создаёте транзакцию. В общем, LiveWire скрывает эти различия и переводит приложение в режим autocommit, если приложение не использует beginTransaction для явного старта транзакции. Для ANSI-БД Informix, LiveWire не использует autocommit. Для этих БД приложение всегда использует транзакции, даже если никогда явно не вызывает beginTransaction. Приложение обязано использовать commitTransaction или rollbackTransaction для завершения транзакции. Настоятельно советуем всегда использовать явный контроль транзакций при выполнении изменений в БД. Это гарантирует, что изменения будут сделаны или отменены вместе. Кроме того, при использовании обновляемых курсоров Вы также всегда должны использовать явные транзакции для контроля за целостностью Ваших данных в период между чтением данных (с помощью next) и их изменением (с помощью insertRow, updateRow или deleteRow). Использование явного контроля транзакций и обновляемых курсоров необходимо для того, чтобы исключить ошибки в некоторых БД, таких как Oracle и Informix. Использование Методов Управления Транзакциями Используйте следующие методы объектов database или Connection для явного управления транзакциями:
Сервис LiveWire Database Service не поддерживает вложение транзакций. Если Вы вызовете beginTransaction несколько раз до подтверждения или отката первой открытой Вами транзакции, Вы получите ошибку. Для объекта database максимум области видимости транзакции ограничен текущим клиентским запросом (HTML-страницей) в приложении. Если приложение существует на странице до вызова метода commitTransaction или rollbackTransaction, то транзакция автоматически подтверждается или откатывается на основе установок параметра commitflag, задаваемого при соединении с БД. Для объектов Connection область видимости транзакции ограничена периодом существования этих объектов. Если Вы освобождаете соединение или закрываете пул соединений до вызова методов commitTransaction или rollbackTransaction, то транзакция автоматически подтверждается или откатывается на основе установок параметра commitflag, задаваемого при соединении с БД методом connect или в конструкторе DbPool. Если текущая транзакция отсутствует (то есть, если приложение не вызывало beginTransaction), вызовы методов commitTransaction и rollbackTransaction могут привести к ошибке в БД. Транзакция может работать с разными объёмами данных. Пример из раздела "Изменение Информации Базы Данных" создаёт одну транзакцию для модифицирования всех рядов курсора. Если в Вашем курсоре небольшое количество рядов, такой подход будет оправданным. Если, однако, Ваш курсор возвращает тысячи рядов, Вы можете обработать этот курсор в нескольких транзакциях. Такой подход снизит размер транзакций и улучшит доступ к информации. Если Вы разбиваете Ваш процесс на несколько транзакций, убедитесь, что вызов next и ассоциированный вызов updateRow или deleteRow происходят внутри одной транзакции. Если Вы получаете ряд в одной транзакции, завершаете её, а затем пытаетесь обновить или удалить ряд, Вы можете получить ошибку в БД. Выбор способа обработки транзакции зависит от целей Вашего приложения. Нужно обратиться к документации создателя БД для получения информации о том, как использовать транзакции для данного типа БД. |
|||||||||||||||||||||
Работа с Двоичными/Бинарными Данными | |||||||||||||||||||||
Двоичные данные для мультимедиа-содержимого, такого как изображение или звуковой файл, хранятся в БД в виде большого двоичного объекта/binary large object (BLOb). Можно использовать технику двух видов для обработки бинарных данных в приложениях JavaScript:
Если Вам не нужно хранить BLOb-данные в БД, Вы можете хранить в БД имена файлов и осуществлять доступ к этим файлам в Вашем приложении с помощью стандартных тэгов HTML. Например, если Вы хотите вывести изображение в каждом ряду таблицы БД, Вы можете создать в таблице столбец с названием imageFileName, содержащий имя нужного файла изображения. Затем можно использовать такое выражение HTML для показа изображения в каждом ряду: <IMG SRC=`mycursor.imageFileName`> Когда курсор проходит по таблице, имя файла в тэге IMG изменяется на ссылку на соответствующий файл. Для того чтобы Вы могли манипулировать реальными двоичными данными в Вашей БД, машина выполнения JavaScript распознаёт значения столбца, являющиеся BLOb-данными. То есть, когда программа создаёт объект Cursor, если один из столбцов таблицы БД содержит BLOb-данные, программа создаёт Blob -объект для соответствующего значения в объекте Cursor. Вы можете затем использовать методы Blob -объектов для отображения этих данных. Также, если нужно вставить BLOb-данные в БД, программа предоставляет Вам для использования глобальную функцию. В таблице показаны методы и функции для работы с BLOb-данными.
Метод blobImage вызывает BLOb из БД, создаёт временный файл специфицированного формата и генерирует HTML-тэг IMG, который ссылается на временный файл. Машина выполнения удаляет временный файл после генерации страницы и отправки её клиенту. Метод blobLink вызывает BLOb-данные из БД, создаёт временный файл и генерирует гипертекстовую ссылку HTML на этот временный файл. Машина выполнения удаляет временный файл после того как пользователь щёлкнет на ссылке или через 60 секунд после того как запрос будет выполнен. Следующий пример иллюстрирует использование blobImage и blobLink для создания временных файлов. В данном случае таблица FISHTBL содержит 4 столбца: ID(ентификатор), name/имя и два изображения. Одно из них является уменьшенной копией/thumbnail изображения; другое - большим изображением. Код записывает HTML для отображения имени, уменьшенной копии и ссылки на большое изображение. cursor = connobj.cursor ("select * from fishtbl"); Если FISHTBL содержит ряды для 4 рыб, пример может дать на выходе такой HTML: Cod <IMG SRC="LIVEWIRE_TEMP9"> Если Вам нужно добавить BLOb-данные в БД, используйте глобальную функцию blob. Она вводит BLOb-данные в столбец в обновляемом курсоре. В противоположность blobImage и blobLink, функция blob является функцией верхнего уровня, а не методом. Следующие операторы вставляют BLOb-данные в столбцы ряда, а затем обновляют этот ряд таблицы FISHTBL в БД. В курсоре имеется единственный ряд. // Начало транзакции. Помните, что backslash (\) это escape-символ в JavaScript. Исходя из этого, Вы обязаны использовать двойной обратный слэш в именах файлов NT, как было в данном примере. |
|||||||||||||||||||||
Вызов Хранимых Процедур | |||||||||||||||||||||
Хранимые процедуры являются неотъемлемой частью работы с реляционной БД. Они являются средством автоматизации часто выполняемых процессов, но их использование даёт также и некоторые другие преимущества:
Работа хранимых процедур имеет отличия на разных БД, поддерживаемых сервисом LiveWire Database Service. Самое важное для LiveWire - это отличия в передаче информации в и из хранимой процедуры в приложении на JavaScript. Вы всегда используете параметры ввода хранимой процедуры для передачи информации в хранимую процедуру. Концептуально имеются несколько способов, которыми можно запросить информацию из хранимой процедуры. Не всегда производитель БД даёт возможность запрашивать информацию любым их этих способов. Хранимая процедура может выполнять один или более операторов SELECT, запрашивая информацию из БД. Вы можете представить эту информацию как виртуальную таблицу, очень похожую на курсор "только для чтения". LiveWire использует класс Resultset как контейнер рядов, возвращаемых одним оператором SELECT хранимой процедуры. Если хранимая процедура допускает наличие нескольких операторов SELECT, Вы получите отдельные объекты Resultset для каждого оператора SELECT. Метод resultSet класса Stproc используется для получения результирующего набора объектов, а затем методы этих объектов используются для манипулирования результирующим набором. БД различных производителей возвращают результирующий набор по-разному:
Параметры Вывода и Ввода/Вывода Помимо стандартных параметров ввода, некоторые производители БД разрешают вводить другие типы параметров для хранимых процедур. Параметры вывода хранят информацию при возвращении из хранимой процедуры и параметры ввода/вывода, передающие и возвращающие информацию. Для большинства БД Вы используете методы outParamCount и outParameters класса Stproc для доступа к параметрам вывода и ввода/вывода. Informix, однако, не разрешает параметры вывода и ввода/вывода. Соответственно, Вы не должны использовать методы outParamCount и outParameters с хранимыми процедурами Informix. Как и вызов функции, хранимая процедура может иметь возвращаемое/return значение. Для Oracle и Sybase это return-значение является дополнением к возвращаемому результирующему набору. Метод returnValue класса Stproc используется для доступа к return-значению. Однако return-значения для хранимой процедуры Informix используются для генерации её результирующего набора. Поэтому returnValue всегда возвращает null для хранимых процедур Informix. Помимо этого, return-значения недоступны для хранимых процедур ODBC и DB2. Этапы Использования Хранимых Процедур После установки соединения с БД этапы использования хранимой процедуры в Вашем приложении несколько различаются для разных БД:
Заметьте, что для разных БД Вы можете завершить выполнение Вашей хранимой процедуры получением return-значения или доступом к параметрам вывода. После того как одно их этих двух действий выполнено, Вы не можете больше работать с результирующим набором, созданным при выполнении хранимой процедуры. В следующих разделах эти этапы рассматриваются по отдельности. Регистрация Хранимой Процедуры Этот этап выполняется только в DB2. В DB2 имеются различные системные таблицы, в которые Вы можете записать Вашу хранимую процедуру. В общем, вставка хранимой процедуры в эти таблицы не обязательна. Однако, для того чтобы использовать Вашу хранимую процедуру с LiveWire, Вы обязаны создать вхождения в этих таблицах. Этот этап выполняется вне приложения JavaScript. Для обычного DB2-сервера Вы обязаны создать системную таблицу DB2CLI.PROCEDURES и ввести в неё Ваши DB2-хранимые процедуры. DB2CLI.PROCEDURES это таблица-псевдокаталог. Если Ваш DB2 предназначен для IBM MVS/EA версии 4.1 или более поздней, Вы обязаны определить имена Ваших хранимых процедур в таблице-каталоге SYSIBM.SYSPROCEDURES. Не забывайте, что Вы используете C, C++ или другой язык для написания DB2-хранимой процедуры. Типы данных, которые Вы используете в этих языках, не соответствуют типам данных, доступным в DB2. Следовательно, если Вы добавляете хранимую процедуру в DB2CLI.PROCEDURES или в SYSIBM.SYSPROCEDURES, убедитесь, что записаны соответствующие типы данных DB2 для параметров хранимой процедуры, а не типы данных исходных языков. Информацию о типах данных DB2 и о том, как сделать вхождения в таблицах, см. в документации по DB2. Определение Прототипа для Хранимой Процедуры Этот этап относится только к пользовательским и системным хранимым процедурам DB2, ODBC и Sybase. Вам не нужно определять прототип хранимых процедур БД Oracle или Informix. Для DB2, ODBC и Sybase программа не может определить в процессе выполнения, предназначен определённый параметр для ввода, вывода, или для того и другого. Соответственно, после того как Вы подключились к БД, Вы обязаны создать прототип, предоставляющий информацию о хранимой процедуре, которую Вы хотите использовать, через метод storedProcArgs объекта database или DbPool. Вам нужно использовать по одному прототипу для каждой хранимой процедуры Вашего приложения. Программа игнорирует дополнительные прототипы для одной и той же процедуры. В прототипе Вы предоставляете имя хранимой процедуры и тип каждого из её параметров. Параметр обязан быть: для ввода/input (IN), вывода/output (OUT), а для ввода и вывода - (INOUT). Например, чтобы создать прототип для хранимой процедуры newhire, имеющей два параметра ввода и один параметр вывода, можно использовать такой вызов метода: poolobj.storedProcArgs("newhire", "IN", "IN", "OUT"); |
|||||||||||||||||||||
Выполнение Хранимой Процедуры | |||||||||||||||||||||
Этот этап применяется ко всем хранимым процедурам. Для выполнения хранимой процедуры Вы создаёте Stproc -объект, используя метод storedProc объектов database или Connection. Создание такого объекта автоматически вызывает хранимую процедуру. При создании объекта хранимой процедуры Вы специфицируете имя процедуры и любые параметры процедуры. Например, у Вас есть хранимая процедура newhire, принимающая параметры - строку и целое число. Следующий вызов метода создаёт spObj -объект хранимой процедуры и вызывает хранимую процедуру newhire: spObj = connobj.storedProc("newhire", "Fred Jones", 1996); В общем, Вы обязаны предоставить значения для всех параметров ввода/вывода для хранимой процедуры. Если хранимая процедура имеет значение по умолчанию, определённое для одного из её параметров, Вы можете использовать директиву "/Default/" для специфицирования этого значения по умолчанию. Аналогично, если хранимая процедура может принимать null-значение одного из своих параметров, Вы можете специфицировать это null-значение либо директивой "/Null/", либо передав само null-значение. Например, предположим, хранимая процедура demosp принимает два строковых параметра и один целочисленный. Вы можете предоставить эти параметры таким образом: spobj = connobj.storedProc("demosp", "Param_1", "Param_2", 1); Альтернативно, чтобы передать null для второго параметра и использовать значение по умолчанию для третьего параметра, Вы можете использовать один из следующих операторов: spobj = connobj.storedProc("demosp", "Param_1",
"/Null/", "/Default/"); :В Informix значения по умолчанию обязаны появляться только после всех специфицированных значений. Например, Вы не можете использовать /Default/ для второго параметра процедуры, а затем специфицировать значение для третьего параметра. Вы можете также использовать директивы "/Default/" и "/Null/" для параметров ввода/вывода. В Oracle хранимая процедура может принимать ref -курсоры как параметры input/output или как output-параметры. Например, у Вас имеется хранимая процедура Oracle под названием proc1, принимающая 4 параметра: ref -курсор, целочисленное значение, другой ref -курсор и другое целочисленное значение. Вызов этой хранимой процедуры из SQL Plus может выглядеть так: Однако, если Вы вызываете эту процедуру из приложения JavaScript, Вы не предоставляете ref -курсор-параметры. Вместо этого эквивалент может быть таким: spobj = connobj.storedProc("proc1", 3, 5); Параметры вывода не могут быть null; однако Вы можете присвоить null-значение параметрам ввода или ввода/вывода. В таблице дано резюме по методам объекта хранимой процедуры.
|
|||||||||||||||||||||
Работа с Результирующими Наборами | |||||||||||||||||||||
Этот этап применяется ко всем хранимым процедурам. Разные БД возвращают результирующие наборы разными способами. Например, у Вас имеется таблица CUSTINFO со столбцами id, city и name. В Sybase Вы можете использовать такую процедуру для получения первых 200 рядов таблицы: create proc getcusts as Если CUSTINFO является таблицей Informix, эквивалентная процедура в Informix
может быть: define rcity, rname char (15); Если CUSTINFO - таблица Oracle, эквивалентная процедура Oracle может быть: create or replace package orapack as Во всех случаях Вы создаёте resultSet -объект для получения информации из хранимой процедуры. Вы делаете это через использование метода resultSet объекта хранимой процедуры так: resObj = spObj.resultSet(); Как и для Cursor -объектов, resultSet -объекты содержат текущий ряд, то есть ряд, на котором стоит указатель в результирующем наборе. Вначале указатель позиционирован перед первым рядом результирующего набора. Чтобы увидеть значения рядов результирующего набора, Вы используете метод next для перемещения указателя по рядам результирующего набора, как показано в следующем примере: spobj = connobj.storedProc("getcusts"); До тех пор, пока в результирующем наборе имеется следующий ряд, метод
next возвращает true и перемещает указатель к следующему ряду. Если указатель
достиг последнего ряда результирующего набора, метод next возвращает false. spobj = connobj.storedProc("getcusts"); Вы можете использовать позицию столбца для результирующих наборов любой БД, а не только с Informix и DB2. Вы можете использовать имя столбца для хранимой процедуры всех типов БД, а не только Informix или DB2. Несколько Результирующих Наборов Хранимая процедура Sybase, Oracle, DB2 или ODBC может создавать несколько результирующих наборов. В этом случае хранимая процедура предоставляет один resultSet -объект для каждого набора. Предположим, Ваша хранимая процедура выполняет такие операторы SQL: select name from customers where id = 6767 Методы и Свойства Результирующего Набора В таблице дано резюме по методам и свойствам класса Resultset
resultSet -объект является объектом "только для чтения"/read-only, объектом последовательного стиля/sequential-style. Исходя из этого, класс не имеет методов insertRow, deleteRow и updateRow, определённых для Cursor -объектов. Когда Можно Использовать Результирующие Наборы Объект resultSet не является бесконечно действующим. Вообще, когда хранимая процедура стартует, не допускается никакое взаимодействие между клиентом БД и сервером БД, пока хранимая процедура не завершит выполнение. Есть три ситуации, когда результирующий набор является недействующим:
|
|||||||||||||||||||||
Работа с Return-Значениями | |||||||||||||||||||||
Этот этап относится к хранимым процедурам Sybase и Oracle. Для процедур Informix, ODBC и DB2 метод returnValue всегда возвращает null. Если Ваша хранимая процедура возвращает значение (return value), Вы можете
получить к нему доступ с помощью метода returnValue. Для DB2, ODBC и Sybase Вы обязаны запросить resultSet -объекты до вызова метода returnValue. После того как Вы вызвали returnValue, Вы больше не сможете получить данные из результирующего набора и не сможете получить какие-либо дополнительные результирующие наборы. Вы должны вызывать returnValue после того, как обработали результирующий набор, но до запроса параметров вывода. |
|||||||||||||||||||||
Работа с Параметрами Вывода | |||||||||||||||||||||
Этот этап касается хранимых процедур Sybase, Oracle, DB2 или ODBC. Для процедур Informix методы, обсуждаемые здесь, не применяются. Чтобы определить количество параметров вывода процедуры (включая параметры и вывода, и ввода/вывода), Вы используете метод outParamCount. Вы можете работать с параметрами вывода хранимой процедуры, используя метод outParameters объекта. Если outParamCount возвращает 0, хранимая процедура не имеет параметров вывода. В этой ситуации не вызывайте outParameters. Например, предположим, Вы создали хранимую процедуру, которая находит фамилию служащего по заданному ID. Если имеется фамилия служащего, ассоциированная с данным ID, процедура возвращает 1, и её output-параметр содержит фамилию служащего. Иначе параметр вывода является пустым. Следующий код выводит фамилию служащего или сообщение о том, что фамилия не найдена: id = 100; Предположим, хранимая процедура имеет один параметр ввода, один параметр ввода/вывода и один параметр вывода. Далее примем, что вызов хранимой процедуры отсылает значение параметра ввода и параметра ввода/вывода, как показано здесь: spobj = connobj.storedProc("myinout", 34, 56); Метод outParameters возвращает любые параметры ввода/вывода до того как возвратит первый параметр вывода. В предыдущем примере, если Вызывается outParameters(1), возвращается значение, возвращаемое хранимой процедурой. И наоборот, если вызывается outParameters(0), метод возвращает 56. Это значение, переданное хранимой процедуре в позиции параметра ввода/вывода. Параметры вывода не могут быть null; однако Вы можете присвоить null-значение параметра ввода или ввода/вывода. В DB2, ODBC и Sybase Вы обязаны запрашивать resultSet -объекты и использовать метод returnValue до того, как вызываете outParameters. После того как Вы вызвали returnValue или outParameters, Вы больше не сможете получить данные из результирующего набора и не сможете получить какие-либо дополнительные результирующие наборы. Вы должны вызывать outParameters после обработки результирующего набора и любых return-значений. |
|||||||||||||||||||||
Исключения Informix и Sybase | |||||||||||||||||||||
Хранимые процедуры Informix и Sybase могут возвращать коды ошибки, используя механизм исключений. После того как Вы запустили процедуру на выполнение, Вы можете запрашивать эти коды ошибок и сообщения об ошибках, используя методы majorErrorCode и majorErrorMessage ассоциированного объекта database или Connection. Например, у Вас имеется хранимая процедура Informix: create procedure usercheck (user varchar(20)) Если Вы запустите эту процедуру на выполнение, Вы сможете проверять, появилась ли ошибка, а затем получить доступ к коду ошибки и сообщению о ней: spobj = connobj.storedProc("usercheck"); |