![]() |
|
||
|
|
|
Использование технологий Java в Oracle 8i(Николай Зенькевич) Хранимые процедуры Java в Oracle 8i. Введение. Компания Oracle давно и активно внедряет в свои технологии язык программирования Java. Революционным новаторством в этой области стал выпуск новой версии сервера базы данных Oracle 8i и Oracle Application Server. До 8i язык Java если и присутствовал в продуктах Oracle , то был как бы дополнительной возможностью к основному языку PL\SQL. Но начиная с этой версии он встал наравне, а во многом даже и впереди PL\SQL. Требуется учесть наличие гораздо более широких возможностей Java по сравнению с PL\SQL (многопоточность, динамическую загрузку классов, сетевые возможноcти и др.), а также большее число библиотек и разработчиков Java. Язык Java был выбран не случайно. Во-первых, язык Java кроссплатформенен (существуют JDK для всех платформ поддерживаемых Oracle). Во-вторых, Java, также как и Oracle, обладает высокой степенью безопасности (Java 2 Security), что позволяет безопасно выполнять код Java внутри базы данных. Поддержку Java кода внутри базы данных Oracle осуществила путем включения в состав базы данных JServer. Следует отметить, что за богатство новых возможностей естественно приходится платить – возросшие требования к конфигурации сервера или же снижение скорости. JServer. Как уже отмечалось, для поддержки Java на сервера базы данных в его состав был включен JServer– сервер Java, который отвечает за загрузку java-классов в базу данных, компиляцию java кода, безопасность выполнения приложений. На рисунке изображена схема JServer: ![]() JServer включает в свой состав виртуальную машину Java Aurora, именно она и выполняет Java код. JServer также включает в свой состав все классы JRE, причем для повышения производительности многие из них представляют собой native код. Также для повышения производительности Aurora использует JIT (just-in-time) предкомпилятор, который компилирует байт код java в native код и только затем он выполняется. Это повышает производительность в 2-10 раз, но сильно загружает систему. Также возможно подключение внешних акселераторов Java. К особенностям Java программирования под JServer следует отнести невозможность подключения пользовательского native кода из соображений безопасности, невозможность работы с графическим выводом (можно создавать графические объекты, но нельзя их визуализировать). Для соединения с базой данных, в которой выполняется Java код, хотя и используется JDBC, но JDBC-соединение уже не сессия в базе данных, а простой внутренний канал сессии, в которой выполняется код. Такое соединение открывается практически мгновенно и работает очень быстро, кроме этого исчезла необходимость отслеживать закрытие, а также коммит и роллбэк для каждого соединения – это можно проделать в любом соединении для всей сессии. Для соединений с другой базой данных нельзя применять OCI драйвер (так как нельзя использовать пользовательский native код). Однако включена более быстрая поддержка Thin драйвера. К проблемным моментам следует отнести нечеткое соблюдение приоритетов потоков. Эта проблема возникла из-за большой загрузки сервера JIT предкомпилятором. К главным особенностям выполнения Java на JServer следует отнести принцип работы JVM Aurora. JServer имеет свою JVM Aurora, однако для каждой сессии, при первом обращении к Java коду, запускается своя отдельная JVM Aurora с правами, которыми обладает пользователь открывший соединение. Каждая JVM имеет свою память и загруженные классы. Таким образом, классы загружаться в память для каждой сессии, однако, это не сказывается на скорости, так как все классы находятся в базе данных. Можно условно считать, что переменная CLASSPATH установлена на корень хранилища Java объектов некоторых схем базы данных. В базе данных могут находиться не только исходный код Java и классы, но и другие ресурсы, например сериализированные объекты или файла свойств. Две Java сессии не могут взаимодействовать между собой, кроме как через объекты базы данных (последовательности, таблицы и др.) Это существенно для работы Web серверов. Также следует помнить, что статические переменные в каждой сессии инициализируются заново. Данная сложность работы JVM хотя и требует значительного объема памяти сервера и других ресурсов, но при этом значительно повышает безопасность выполнения Java приложений внутри базы данных, а также упрощает сборку мусора (очистку памяти от ненужных объектов). ![]() При окончании Java сессии соответствующая JVM уничтожается. Окончание Java сессии происходит при окончании сессии в базе данных, при тайм-ауте или при вызове:
пользовательским приложением. Если какой-то класс, используемый сессией, изменился в течение сессии (был изменен его исходный код, хранящийся в базе данных, или он сам был создан заново), то при следующем обращении к Java будет выдана ошибка и начата новая сессия. Ограничение возможностей java приложений,
безопасность. Как отмечалось Java имеет гораздо больше возможностей чем PL\SQL. Следовательно, возникает необходимость ограничения этих возможностей некоторым пользователям. Каждой схеме базы данных могут быть присвоены персональные разрешения на выполнение определенных действий в Java приложениях. Для запуска Java схеме не требуется особых прав. Для проверки прав Java используется принцип «что не разрешено,то запрещено». Для раздачи прав на выполнения какой-либо операции используется два метода: выдача Java-роли схеме или прямая выдача конкретного права одного из типов разрешений.
Таким образом, можно выдать права на чтение/запись в конкретный файл или каталог, открытие сокета, сериализацию объекта, изменение свойств JVM, чтение свойств класса, раздачу Java прав и др. Раздача и отбор прав Java прав может производиться двумя способами, через SQL и Java. Для раздачи Java прав через SQL существует специальный пакет dbms_java. Он содержит несколько десятков процедур. Вот две основные из них:
Grantee – схема, которой выдается разрешение. Permission_type – тип разрешения. Permission_name – имя разрешения. Permission_action – разрешаемые действия. Пример выдачи права схеме WWW на запись и чтение в каталоге D:\www, кроме файла password.txt.
Требуется помнить, что после сеанса раздачи и отбора прав, необходимо выполнять коммит, так как все изменения происходят в таблице SYS.JAVA$POLICY$ (там можно посмотреть розданные права, однако лучше напрямую не производить изменений). Для раздачи прав через Java существует класс с аналогичными статическими методами oracle.aurora.rdbms.security.PolicyTableManager. Существует возможность создавать свои типы разрешений и сами разрешения. Хранимые Java процедуры. Создание хранимой Java процедуры обязательно происходит по следующей схеме. ![]()
Публикация представляет собой создание простой (PL\SQL) хранимой процедуры, которая ссылается на статический метод загруженного класса. Процесс разработки рассматривать не будем. Остановимся лишь на результате: результатом разработки должен стать исходный код Java класса (или нескольких классов), который должен содержать хотя бы один статический метод для дальнейшей публикации. Для создания хранимой процедуры желательно чтобы статический метод возвращал void, однако, это не обязательно – он может возвращать любой объект, но он будет теряться. Для создания функции необходимо, чтобы метод возвращал объект Java-типа, имеющем аналог в SQL. Таблица соответствия SQL типов – Java типам.
Исключения, вызываемые Java кодом и необрабатываемые им, успешно обрабатываются следующим способом:
Как уже сообщалось, загрузка может производиться двумя основными способами. Загрузка командой SQL CREATE JAVA может осуществляться из SQL*Plus или другой SQL оболочки. Для выполнения этой команды надо иметь системную привилегию CREATE PROCEDURE и CREATE TABLE. Существует три типа команды CREATE JAVA (CLASS, SOURCE, RESOURCE) для создания соответственно класса из поля типа LOB или JAVA SOURCE, исходного кода Java и Java ресурса (картинки, файла свойств, файла сериализированного объекта) из поля типа LOB или текста самой команды. Для создания кода хранимой процедуры можно использовать CREATE JAVA SOURCE - для загрузки исходного кода и дальней его компиляции JServerом или CREATE JAVA CLASS для загрузки скомпилированного класса из поля BFILE, что более сложно, так сначала класс все равно нужно загрузить через loadjava. Синтаксис CREATE JAVA SOURCE проще объяснить на простом примере, тем более что многие опций не применяются очень редко. Опции позволяют автоматически скомпилировать код, разрешить его использование в других схемах или же не создавать source, если его не удалось скомпилировать, установить CLASSPATH на другие схемы, а также определить от чего имени будет выполняться код: от имени и с правами вызвавшего или же создавшего.
Эта команда просто создаст Java Source в текущей схеме и будет иметь в виду, что класс test_me храниться в нем, что не позволит создать класс с таким же именем в другом Java Source. Для загрузки кода через утилиту loadjava требуется те же права, как для CREATE JAVA, а также возможность записи в таблицу JAVA$CLASS$MD5$TABLE, которая находится в схеме пользователя и хранит информацию о классах. Эта информация используется для отслеживания изменений в классах, чтобы во время перекомпилировать классы или заново не загружать старую версию при повторной загрузке. Загрузка классов loadjava может осуществляться через BLOB поля таблиц, однако в этом нет никаких преимуществ, кроме более удобного отслеживания хранилища классов, ручные изменения которых могут привести к невосстанавливаемым потерям. Для установки ссылок на такие поля используется таблица CREATE$JAVA$LOB$TABLE. Утилита loadjava имеет такие же опции, что и CREATE JAVA, плюс дополнительные. Такие как, строка соединения с базой данных, используемый при этом драйвер, загружать все указанные файлы или только обновленные, создавать ли public синонимы для загружаемых объектов и др. Сама утилита входит в состав клиента Oracle 8i. Пример использования утилиты loadjava:
Данная команда, выполненная в окне сеанса DOS на рабочей станции, соединится с базой данных, TNS имя которой FR10, с именем SCOTT и паролем TIGER и загрузит в схему SCOTT класс test_me, хранящийся в текущей директории, отображая лог процесса на экране (опция verbose). Следует отметить, что возможно создание и компиляция Java объектов в других схемах. Таким образом, можно использовать библиотечные классы, загруженные в какую-либо схему. При этом для их использования надо будет либо создать синонимы, либо разрешить их при компиляции (установить CLASSPATH на нужную схему). Удаление объектов Java из базы данных происходит при помощи команды DROP JAVA или утилиты dropjava. За этапом загрузки следует этап публикации. Как уже отмечалось, публикация представляет собой создание простой (PL\SQL) хранимой процедуры, которая ссылается на статический метод загруженного класса. Эта процедура может представлять собой самостоятельную хранимую процедуру или функции, процедуру или функцию в пакете или метод объекта, для создания которых, естественно, требуются соответствующие привилегии. Синтаксис команд создания Java процедур такой же, как и при создании обычной хранимой процедуры, отличается только описание тела процедуры. Что проще пояснить на примере создания хранимой функции на основе созданного source:
Следует отметить, что компиляция класса test_me будет произведена автоматически при первом обращении к нему, в данном случае вызове функции getHello. Если пересоздать java source testjava и вызвать функцию getHello, то возникнет ошибка – java сессия будет прервана и запущена новая. Пример обращения к хранимой Java процедуре:
Также следует подметить, что имя java классов используется полное: java.lang.String, хотя компилятор понял бы и сокращенное: String, но Oracle настойчиво рекомендует использовать полные имена. Приведем пример создания хранимой процедуры с передаваемыми параметрами и возвращаемыми параметрами:
В данном классе содержится два статических метода и статическое поле, в котором будет храниться данные между вызовами второго и первого метода. Первый метод сохраняет запрос в статическом поле, выполняет его, записывает значение из первого столбца первой строки результата в таблицу TEST и возвращает его. Второй метод вызывает первый метод, но ничего не возвращает. Для работы с таблицами базы данных используется соединение по умолчанию «jdbc:default:connection:», которое, как уже говорилось, представляет внутренний канал базы данных. Скрипт опубликования процедур:
Скрипт для проверки работоспособности процедур:
Следует обратить внимание на то, что для создания OUT параметра в Java методе пришлось передавать параметр как массив – это стандартный метод создания возвращаемых параметров в Java. Также следует обратить внимание на обработку исключительных ситуаций (try{} – catch(Exception e){}) – сообщение об ошибке будет записано в поток System.out, который по умолчанию направлен в trace файл базы данных. Использование SQLJ для ускорения разработки хранимых Java
процедур. Oracle позаботилась о разработчиках и создала специальную возможность ускорения для разработки Java приложений, обращающихся к базе данных используя статический SQL. Эта возможность получила название «Embedded SQL in Java» или SQLJ. Первое название полностью определяет сущность SQLJ: он позволяет по определенным правилам внедрить SQL код внутрь кода Java, затем транслировать его в чистый код Java(один или несколько классов) и файлы сериализованных объектов и только после этого скомпилировать их до байт-кода. Схематично это можно изобразить так: ![]() JServer автоматически распознает SQLJ Java source и выполняет SQLJ трансляцию. Также это можно проделать и на рабочей станции (JDeveloper выполняет это автоматически при обычной компиляции). Приведем пример использования SQLJ на сервере (клиентская использование SQLJ требует соединения с базой данных перед выполнением кода SQLJ). Следует отметить, что SQLJ может применяться для работы не только с базой данных Oracle, а также может использоваться для создания SQLJ - JSP. СозданиеSQLJ Java source:
Публикация через функцию ничем не отличается от обычной:
Теперь сделав выборку:
получим список имен и типов всех Java объектов задействованных в работе данного примера SQLJ. Это был простой пример использования SQLJ. На самом деле SQLJ содержит большое число возможностей.
PL\SQL против JAVA.После всего сказанного встает вопрос: «Так что же лучше использовать, для написания хранимых процедур базы данных Oracle 8i PL\SQL или Java ?» Однозначного вопроса не дает даже сама корпорация Oracle. Но правда, дает совет: если есть необходимость создать сложный объект делающий сложные математические вычисления, работающий с сетевыми ресурсами, XML, файловой системой, LOB полями или же представляющий собой какой-либо Web объект, то лучше использовать Java и не мудрить с PL\SQL. Однако использовать Java для написания простого инсерта по срабатыванию триггера не стоит. Список использованной литературы:
Об
авторе |
| Справка | Условия | |
| В начало | Логин | Комментарий к колонке | Поиск | Почта |