Что такое пакеты в PL/SQL Oracle
Пакет представляет собой сгруппированный по определенным правилам именованный набор элементов кода PL/SQL. Он обеспечивает логическую структуру для организации программ и других элементов PL/SQL: курсоров, типов данных и переменных. Пакеты обладают очень важными функциональными возможностями, включая возможность сокрытия логики и данных, а также определения глобальных данных, существующих в течение сеанса.
Для чего нужны пакеты?
Пакеты — очень важная составная часть языка PL/SQL, краеугольный камень любого сложного проекта. Чтобы это понять, необходимо рассмотреть основные преимущества пакетов.
- Упрощение сопровождения и расширения приложений. По мере того как все большая часть кодовой базы перемещается в режим сопровождения, качество приложений PL/SQL определяется не только их производительностью, но и простотой сопровождения. С этой точки зрения пакеты играют исключительно важную роль, поскольку они обеспечивают инкапсуляцию кода (в частности, они позволяют скрыть команды SQL за интерфейсом процедур), дают возможность определять константы для литералов и «волшебных» чисел, и группировать логически связанные функции. Пакетный подход к проектированию и реализации сокращает количество потенциальных сбоев в приложениях.
- Повышение производительности приложений. Во многих ситуациях использование пакетов повышает производительность и эффективность работы приложений. Определение постоянных структур данных уровня пакета позволяет кэшировать статические значения из базы данных. Это дает возможность избежать повторных запросов, а следовательно, значительно ускорить получение результата.
- Исправление недостатков приложений или встроенных элементов. Некоторые из существующих программных компонентов Oracle имеют недостатки; в частности, не лучшим образом реализованы важнейшие функции встроенных пакетов UTL_FILE и DBMS_OUTPUT. Мириться с ними не обязательно; можно разработать собственный пакет на базе существующего, исправив как можно больше проблем.
- Снижение необходимости в перекомпиляции кода. Пакет обычно состоит из двух элементов: спецификации и тела. Внешние программы (не определенные в пакете) могут вызывать только программы, перечисленные в спецификации. Изменение и перекомпиляция тела пакета не отражается на работе этих внешних программ. Снижение необходимости в перекомпиляции кода является важнейшим фактором администрирования больших объемов программного кода приложений.
Концепция пакетов очень проста. Единственная сложность заключается в том, чтобы научиться эффективно применять в приложениях их богатые возможности.
Основные концепции пакетов
Прежде чем переходить к подробному изучению синтаксиса и структуры пакетов, следует изучить некоторые концепции пакетов:
- Сокрытие информации. Сокрытие информации о системе или приложении обычно преследует две цели. Во-первых, возможности человека по работе со сложными системами ограничены. Исследования показали, что у среднего «мозга» при запоминании даже семи (плюс/минус двух) элементов в группе возникают проблемы. Таким образом, пользователь (или разработчик) освобождается от необходимости вникать в ненужные подробности и может сосредоточиться на действительно важных аспектах. Во-вторых, сокрытие информации препятствует доступу к закрытым сведениям. Например, разработчик может вызвать в своем приложении готовую функцию для вычисления некоторого значения, но при этом формула вычислений может быть секретной. Кроме того, в случае изменения формулы все модификации будут вноситься только в одном месте.
- Общие и приватные элементы. Концепция общих и приватных элементов тесно связана с концепцией сокрытия информации. Общедоступный код определяется в спецификации пакета и доступен любой схеме, обладающей для этого пакета привилегией EXECUTE. Приватный код виден только в пределах пакета. Внешние программы, работающие с пакетом, не видят приватный код и не могут использовать его.
Приступая к разработке пакета, вы решаете, какие из его элементов будут общими, а какие — приватными. Кроме того, тело пакета можно скрыть от других схем/разработчиков. В таком случае пакет используется для сокрытия деталей реализации программ. Это особенно полезно для изоляции переменных компонентов приложения — фрагментов кода, зависящих от платформы, часто меняющихся структур данных и временных обходных решений.
На ранних стадиях развития программы в теле пакета также могут реализоваться в виде «заглушек» с минимальным объемом кода, необходимым для компиляции пакета. Этот прием позволяет сосредоточиться на интерфейсах программы и их взаимных связях.
- Спецификация пакета. Она содержит определения всех общедоступных элементов пакета, на которые можно ссылаться извне. Спецификация напоминает большой раздел объявлений; она не содержит блоков PL/SQL или исполняемого кода. Из хорошо спроектированной спецификации разработчик может получить всю необходимую для использования пакета информацию и ему никогда не придется заглядывать «за интерфейс» (то есть в тело пакета, содержащее реализацию его компонентов).
- Тело пакета. Здесь находится весь код, который необходим для реализации элементов, определенных в спецификации пакета. Тело может содержать отсутствующие в спецификации личные элементы, на которые нельзя ссылаться извне пакета, в частности объявления переменных и определения пакетных модулей. Кроме того, в теле пакета может находиться исполняемый (инициализационный) раздел, который выполняется только один раз для инициализации пакета.
- Инициализация. Концепция инициализации хорошо известна любому программисту, однако в контексте пакетов она имеет особое значение. В данном случае инициализируется не отдельная переменная, а весь пакет путем выполнения кода произвольной сложности. При этом Oracle следит за тем, чтобы пакет инициализировался только один раз за сеанс.
- Постоянство в течение сеанса. Концепция постоянства (или сохраняемости) тоже хорошо знакома программистам. Когда вы подключаетесь к Oracle и выполняете программу, присваивающую значение переменной уровня пакета (то есть переменной, объявленной в пакете вне содержащихся в нем программ), эта переменная сохраняет значение в течение всего сеанса, даже если выполнение присвоившей его программы завершается.
- Также существует концепция сеансового постоянства. Если я подключаюсь к базе данных Oracle (создаю сеанс) и выполняю программу, которая присваивает значение пакетной переменной (то есть переменной, объявленной в спецификации или теле пакета, за пределами всех входящих в него программ), то эта переменная продолжает существовать на всем протяжении сеанса и сохраняет свое значение даже при завершении программы, выполнившей присваивание.
Именно пакеты обеспечивают поддержку структур данных с сеансовым постоянством в языке PL/SQL.
Графическое представление приватности
Различия между общедоступными и приватными элементами пакета дают разработчикам PL/SQL беспрецедентные средства управления структурами данных и программами. Грэди Буч предложил визуальное средство описания этих аспектов пакета (которое было вполне естественно названо диаграммой Буча).
Посмотрите на рисунок ниже. Обратите внимание на надписи «Внутренняя часть» и «Внешняя часть». Первая часть содержит тело пакета (внутренняя реализация пакета), а вторая — все программы, написанные вами и не являющиеся частью пакета (внешние программы).
Несколько выводов, следующих из диаграммы Буча:
- Внешние программы не могут пересекать границу внутренней реализации; иначе говоря, внешняя программа не может обращаться или вызывать элементы, определенные в теле пакета. Это приватные элементы, невидимые за пределами пакета.
- Элементы, определенные в спецификации пакета («Внешняя часть» на диаграмме), располагаются по обе стороны от границы между внутренней и внешней частью. Такие программы могут вызываться внешней программой (из внешней части), они доступны для приватных программ и в свою очередь могут вызывать или обращаться ко всем остальным элементам пакета.
- Общедоступные элементы пакета предоставляют единственный путь к внутренней части. В этом отношении спецификация пакета действует как управляющий механизм для пакета в целом.
- Если окажется, что объект, ранее бывший приватным (например, модуль или курсор), должен стать общедоступным, просто добавьте его в спецификацию и перекомпилируйте пакет. После этого объект станет доступным за пределами пакета.