Архитектура ODMG
Предлагаемая ODMG архитектура показана на рис. 2.1. В этой архитектуре определяются способ хранения данных и разные виды пользовательского доступа к этому “хранилищу данных”17. Единое хранилище данных доступно из языка определения данных, языка запросов и ряда языков манипулирования данными.18 На рис. 2.1 ODL означает Object Definition Language (язык определения объектов), OQL – Object Query Language (язык объектных запросов) и OML – Object Manipulation Language (язык манипулирования объектами).
Рис. 2.1. Архитектура ODMG
Центральной в архитектуре является модель данных, представляющая организационную структуру, в которой сохраняются все данные, управляемые ООСУБД. Язык определения объектов, язык запросов и языки манипулирования разработаны таким образом, что все их возможности опираются на модель данных. Архитектура допускает существование разнообразных реализационных структур для хранения моделируемых данных, но важным требованием является то, что все программные библиотеки и все поддерживающие инструментальные средства обеспечиваются в объектно-ориентированных рамках и должны сохраняться в согласовании с данными.
Основными компонентами архитектуры являются следующие.
Объектная модель данных. Все данные, сохраняемые ООСУБД, структуризуются в терминах конструкций модели данных. В модели данных определяется точная семантика всех понятий (более подробно см. ниже).
Язык определения данных (ODL ). Схемы баз данных описываются в терминах языка ODL , в котором конструкции модели данных конкретизируются в форме языка определения. ODL позволяет описывать схему в виде набора интерфейсов объектных типов, что включает описание свойств типов и взаимосвязей между ними, а также имен операций и их параметров. ODL не является полным языком программирования; реализация типов должна быть выполнена на одном из языков категории OML . Кроме того, ODL является виртуальным языком в том смысле, что в стандарте ODMG не требуется его реализация в программных продуктах ООСУБД, которые считаются соответствующими стандарту.
Допускается поддержка этими продуктами эквивалентных языков определения, включающих все возможности ODL , но адаптированных под особенности конкретной системы. Тем не менее, наличие спецификации языка ODL в стандарте ODMG является важным, поскольку в языке конкретизируются свойства модели данных.
Язык объектных запросов (ODL ). Язык имеет синтаксис, похожий на синтаксис языка SQL, но опирается на семантику объектной модели ODMG . В стандарте допускается прямое использование OQL и его встраивание в один из языков категории OML .
Языки манипулирования объектами (OML ). Для программирования реализаций операций и приложений требуется наличия объектно-ориентированного языка программирования. OML представляется собой интегрирование языка программирования с моделью ODMG ; это интегрирование производится за счет определенных в стандарте правил языкового связывания (language binding ). Дело в том, что в самих языках программирования, естественно, не поддерживается стабильность объектов. Чтобы разрешить программам на этих языках обращаться к хранимым данным, языки должны быть расширены дополнительными конструкциями или библиотечными элементами. Эту возможность и обеспечивает языковое связывание.
В одной ООСУБД могут поддерживаться несколько OML . В стандарте ODMG -2 были специфицированы правила связывания для языков C ++ и Smalltalk 19. Практически завершена работа над спецификаций правил связывания для языка Java.
Постоянноехранилище объектов. Логическая организация хранилища данных любой ООСУБД, совместимой со стандартном ODMG , должна основываться на модели данных ODMG . Физическая организация у разных ООСУБД может различаться, но в любом случае она должна обеспечивать эффективные структуры данных для хранения иерархии типов и объектов, являющихся экземплярами этих типов. Иерархия типов связана не только с данными, но и с различными библиотеками и компонентами инструментальных средств, поддерживающими разработку приложений. Так что в ООСУБД, совместимой со стандартом ODMG , хранилище представляет собой интегрированную систему, где согласованным образом сохраняются данные и программный код.
Инструментальные средства и библиотеки. Инструментальные средства, поддерживающие, например, разработку пользовательских приложений и их графических интерфейсов, программируются на одном из OML и сохраняются как часть иерархии классов. Библиотеки функций доступа, арифметических функций и т.д. также сохраняются в иерархии типов и являются единообразно доступными из программного кода разработчика приложения. Ассортимент инструментальных средств и библиотек в стандарте не определяется.
GemStone
Как отмечалось выше, ООСУБД GemStone была одной из первых коммерчески доступных ООСУБД. Система была разработана компанией Servio -Logic совместно с OGI . В исходном варианте системы разработчики GemStone опирались на язык Smalltalk . Хотя в первых выпусках системы ее основной язык назывался Opal , сразу было видно, что в действительности этого всего лишь Smalltalk с поддержкой стабильного хранения объектов, и вскоре название языка было заменено на GemStone Smalltalk . Впоследствии в GemStone была обеспечена поддержка языков C и C ++, но во все времена базовым языком оставался Smalltalk , а все остальные интерфейсы строились поверх базового. И серверная, и клиентская части системы могут работать под управлением всех основных ветвей ОС UNIX и всех развитых вариантов Windows . В настоящее время продукт поддерживается, развивается и распространяется компанией GemStone Systems Inc. ().
Система основана на трехзвенной архитектуре клиент-сервер, в которой прикладная обработка данных производится на среднем уровне между процессом взаимодействия с пользователем и процессом, поддерживающим хранилище данных. Важность этого подхода состоит в том, что, если в приложении используется много данных, то код приложения целесообразно расположить на стороне хранилища данных, а если в приложении производится много изменений над небольшим объемом данных, то имеет смысл разместить код приложения на стороне пользователя. Тем самым, архитектура позволяет уменьшить объем сетевого трафика без перегрузки сервера, что повышает скорость обработки данных.
Для управления мультидоступом используется механизм транзакций. Механизм основан на так называемом оптимистическом подходе, при котором каждая сессия работает с собственной локальной копией хранилища объектов, и слияние произведенных в сессиях изменений хранилища происходит при завершении транзакции. Если при завершении транзакции обнаруживается, что произведенные в ней изменения конфликтуют с изменениями других ранее зафиксированных транзакций, то фиксация транзакции не производится, транзакция не завершается, и решение проблемы возлагается на пользователя.
Автоматическая блокировка объектов не производится, но пользователь может явно запросить блокировку, что повышает шансы на успешную фиксацию транзакции.
Для обеспечения безопасности данных поддерживается механизм авторизации доступа на уровне владельца объекта и его группы пользователей, так что может быть ограничен доступ к некоторым объектам или некоторым методам объектов. К каждому объекту приписывается авторизационный объект, содержащий данные о том, какие пользователи и в каком режиме (чтения или изменения) имеют доступ к объекту.
Для восстановления базы данных после сбоев аппаратуры используются механизмы репликации, резервного копирования и журнализации. Любой авторизованный пользователь может запросить выполнения полного или частичного копирования. Восстановление базы данных после сбоя системы или дисковых устройств начинается с использования последней по времени резервной копии. После этого при помощи данных, сохраненных в журнальных файлах, хранилище объектов приводится к состоянию, соответствующему последней до момента сбоя зафиксированной транзакции. Авторизованные пользователи могут также запросить поддержку реплицирования областей хранилища данных.
В системе поддерживается целостность по ссылкам между всеми объектами, поскольку все ссылки основываются на использовании объектных идентификаторов, и объекты, для которых существуют ссылки от других объектов, не могут быть удалены. Для повышения скорости доступа к часто используемым коллекциям обеспечивается средство построения индексов.
Объекты делаются стабильными (т.е. сохраняются в базе данных) путем использования своего рода стабильного корня, называемого коннектором. Все объекты, прямо или косвенно достижимые по объектным ссылкам от коннектора, являются стабильными. В GemStone каждого класса, в котором существует хотя бы один стабильный объект, поддерживается эквивалентная серверная версия класса. Другими словами, один вариант класса служит классом в контексте программирования, а другой – в контексте базы данных.
Такие пары поддерживаются автоматически: если создается класс в смысле Smalltalk , и некоторый объект этого класса становится стабильным, то автоматически создается серверный класс этого объекта (класс в смысле GemStone ). Создание коннектора приводит к появлению экземпляра класса GemStone , эквивалентного классу объекта, который должен быть сделан стабильным. Аналогично, любой объект, достижимый от коннектора, автоматически становится стабильным.
В GemStone поддерживается динамическая сборка мусора (garbage collection ). Процесс-“мусорщик” автоматически освобождает память, занимаемую объектами, на которые отсутствуют ссылки.
В среде GemStone можно использовать различные реализации Smaltalk , а также языки C и C ++. Классы и объекты можно создавать с использованием любого из этих языков, и объекты, созданные на одном языке можно использовать в приложениях, написанных на любом другом языке. Реализация языка C представляет собой набор функций и набор компонентов, преобразующих объекты GemStone в указатели и литералы C и наоборот. Реализация C ++ включает препроцессор в чистый С и библиотеку классов.
Подключения к реляционным системам (например, Oracle или IBM DB 2) производятся через шлюзы. Для синхронизации состояния локальной (управляемой GemStone ) и внешних копий данных обеспечивается автоматическая модификация данных. В зависимости среды и требований к уровню синхронизованности эти обновления выполняются немедленно или же в пакетном режиме.
GemStone можно также использовать для управления данными, соответствующими стандартам OLE и CORBA . Для работы с данными в реляционном стиле поддерживаются стандарты SQL и ODBC .
Идентифицируемость объектов
Для баз данных концепция идентифицируемости объектов (object identity ) сравнительно нова 3. Идея состоит в том, что в модели с идентифицируемостью объектов объект существует независимо от его значения. Таким образом, имеется два понятия эквивалентности объектов: два объекта могут быть идентичны (они представляют собой один и тот же объект) или они могут быть равны (они имеют одно и тоже значение). Это влечет две следствия: первое – разделяемые объекты, а второе – изменения объектов.
В модели с идентифицируемыми объектами два объекта могут иметь совместно используемый компонент. Таким образом, схематическим представлением сложного объекта является (ориентированный) граф, в то время как в системе без идентифицируемости объектов таким представлением является (ориентированное) дерево.
Идентифицируемость объектов обеспечивает мощный примитив манипулирования данными, который может служить основой для манипулирования множествами, кортежами или рекурсивными сложными объектами. Поддержка идентифицируемости объектов обеспечивает возможность реализации таких операций, как присваивание объекта, копирование объекта (как глубокое, так и поверхностное) и проверка идентичности объектов и их равенства (как глубокого, так и поверхностного).
Конечно, можно моделировать идентифицируемость объектов в системе, основанной на идентификации посредством значений, путем введения явных идентификаторов объектов. Однако такой подход перекладывает на пользователя бремя обеспечения уникальности идентификаторов объектов и поддержки ссылочной целостности (и это бремя может быть весьма значительным для таких операций, как “сборка мусора”).
Модели с идентифицируемостью объектов являются нормой в императивных языках программирования, где каждый объект, с которым имеет дело программа, идентифицируем и может быть изменен. Идентифицируемость объекта обеспечивается за счет наличия имени переменной или соответствующего физического адреса памяти. Однако эта концепция совершенно нова для чисто реляционных систем, где идентифицируемость кортежей отношения основывается на значениях.
Иерархии классов или типов
Наследование обладает двумя положительными достоинствами. Во-первых, оно является мощным средством моделирования, поскольку обеспечивает возможность краткого и точного описания мира. Во-вторых, эта возможность помогает факторизовать совместно используемые в приложениях спецификации и реализации. 6
Наследование способствует повторному использованию кода, потому что каждая программа находится на том уровне, на котором ее может совместно использовать наибольшее число объектов.
Имеется по крайней мере четыре типа наследования: наследование через подстановку, наследование путем включения, наследование через ограничение и наследование через специализацию.
Наследование через подстановку подразумевает, что тип T наследует от типа T ’ , если над объектами типа T можно выполнить больше операций, чем над объектами типа T ’ . Таким образом, вместо объекта типаT ’ всегда можно подставить объект типа T . Этот тип наследования базируется на поведении, а не на значениях.
Наследование путем включения соответствует понятию классификации. В этом случае утверждается, что тип T является подтипом T ’ , если каждый объект типа T является также объектом типа T ’ . Этот тип наследования базируется на структуре, а не на операциях. Примером является тип “квадрат” с методами “получить”, “установить размер” и “раскрашенный квадрат” с методами “получить”, “установить размер” и “раскрасить”.
Наследование через ограничение является частным случаем наследования путем включения. Тип T является подтипом типа T ’ , если к нему относятся все объекты типа T ’ , которые удовлетворяют данному ограничению. Примером такого наследования является класс “подросток” как подкласс класса “человек”: объекты класса “подросток” не имеют дополнительных полей или операций по сравнению с объектами класса “человек”, но они удовлетворяют более специфичным ограничениям (возраст подростков ограничен снизу 13, а сверху 19 годами). 7
При наследовании через специализацию тип T является подтипом T ’ , если объекты типа T являются объектами типа T ’ , но при этом содержат более конкретные данные. Примером являются типы “люди” и “служащие”, где данные о служащих включают все данные о соответствующих людях, но включают некоторые дополнительные поля.
Существующие системы и прототипы в той или иной мере поддерживают эти четыре типа наследования. Авторы Первого манифеста не хотели навязывать какой-либо конкретный стиль наследования. По всей видимости, только потому, что среди самих них не было общего мнения относительно достоинств и недостатков каждого из подходов. Вообще, Первому манифесту свойственно сглаживание разногласий.
Инкапсуляция
Идея инкапсуляции происходит (а) из потребности отчетливо различать спецификации и реализации операций и (б) из потребности в модульности. Модульность необходима для структурирования сложных приложений, разрабатываемых и реализуемых группой программистов. Она также необходима как средство защиты и авторизации.
Имеются две точки зрения на проблему инкапсуляции: точка зрения с позиций языка программирования (это исходная точка зрения, поскольку отсюда ведет свое начало сама концепция) и адаптация этой точки зрения применительно к базам данных.
Идея инкапсуляции в языках программирования происходит от абстрактных типов данных. С этой точки зрения объект делится на интерфейсную и реализационную части. Интерфейсная часть является спецификацией набора допустимых над объектом операций. Только эта часть объекта видима (для пользователя объекта). Реализационная часть состоит из части данных и процедурной части. Часть данных – это представление (representation ), или состояние объекта, а в процедурной части на некотором языке программирования описывается реализация каждой операции.
Адаптация этого принципа применительно к базам данных состоит в том, что объект инкапсулирует и программу, и данные. В мире баз данных не вполне ясно, является или нет структурная часть типа частью интерфейса (это зависит от системы), в то время как в мире языков программирования структура данных явно является частью реализации, а не интерфейса.
В реляционных системах прикладные программы обычно пишутся на императивном языке программирования с включением в него операторов языка манипулирования данными или на языке четвертого поколения и хранятся в обычной файловой системе, а не в базе данных. Таким образом, при таком подходе имеются кардинальные различия между программой и данными, а также между языком запросов (для незапланированных запросов) и языком программирования (для прикладных программ). 4
В объектно-ориентированных системах имеется единая модель для данных и операций, и информация может быть скрыта.
Никакие иные операции, помимо указанных в интерфейсе, не выполняются. Это ограничение справедливо как для операций изменения, так и для операций выборки.
Инкапсуляция обеспечивает что-то вроде “логической независимости данных”: можно изменить реализацию типа, не меняя каких-либо программ, использующих этот тип. Таким образом, прикладные программы защищены от реализационных изменений на нижних слоях системы.
По мнению авторов Первого манифеста, правильной инкапсуляцией является такая, когда видны только операции, а данные и реализация операций скрыты в объектах. Однако имеются случаи, когда инкапсуляция не нужна, и использование системы может быть значительно упрощено, если система допускает нарушение инкапсуляции при некоторых условиях. Например, при незапланированных запросах инкапсуляция является не столь необходимой, так как такие вопросы, как сопровождаемость, в этом случае не являются важными. Таким образом, ООСБД должна обеспечивать механизм инкапсуляции, но имеются случаи, когда его принудительное использование неуместно.
ITASCA
Распределенная ООСУБД ITASCA основана на результатах проекта Orion , выполнявшегося в MCC . Разработка серии из трех прототипов завершилась выпуском системы, основанной на архитектуре “много клиентов-много серверов”. Система была доведена до уровня коммерческого продукта начинающей техасской компанией, которая в 1995 г. была приобретена компанией IBEX Corp . ().
В распределенной архитектуре ITASCA частные и совместно используемые базы данных разнесены по узлам локальной UNIX -ориентированной сети. Каждой значение данных хранится в одном узле, но централизованное управление отсутствует; все серверы автономны. На каждом сервере поддерживаются кэш страниц и кэш объектов, и каждый сервер множество клиентов с обеспечением мультидоступа на основе блокировок. На клиентах поддерживается только кэш объектов.
Для управления мультидоступом в ITASCA используется двухфазный протокол синхронизационных блокировок с сериализацией транзакций и обнаружением тупиков. Также поддерживаются долгие транзакции на основе перемещения объекта из совместно используемой базы данных в частную базу данных (check -out ). Для обеспечения совместной работы допускается участие нескольких пользователей в одной долгой транзакции.
Для всей распределенной базы данных поддерживается единая схема с использование подсхем для частных фрагментов базы данных. Модель данных включает следующие аспекты:
множественное наследование;
представление классов в виде объектов;
наличие свойств и операций классов;
наличие свойств и операций классов;
поддержка ограничений целостности;
возможность перегрузки операций.
В любое время могут добавляться новые данные, классы, свойства и операции. Для обеспечения контроля над распространением таких операций как удаление объекта имеется возможность определения составных объектов. Для поддержки мультимедийных приложений имеется возможность использования линейных массивных объектов, которые предназначены прежде всего для хранения последовательных данных, таких как текст или аудиоданные.
В пространственных массивных объектах имеются два измерения, и они подходят, например, для хранения изображений.
Восстановление базы данных после сбоев производится на основе журнала, предназначенного для аннулирования результата выполненных операций (undo log ). Это позволяет в процессе восстановления устранить эффект всех транзакций, не завершившихся к моменту сбоя. Фиксация транзакции заключается в том, что на сервере все объекты, измененные данной транзакцией, перемещаются из буфера объектов в буфер страниц.
Поддерживается механизм индексирования, основанный на использовании техники B +-деревьев. Можно создавать индексы для одного класса и одного свойства или для нескольких свойств нескольких классов.
Имеется возможность создания классов, поддерживающих оповещение. Имеются две формы оповещения – пассивная и активная. Пассивное оповещение состоит в том, что сохраняется информация о модификации или удалении экземпляров класса. Приложение может обратиться классу с запросом данных о таких событиях. Активное оповещение приводит к вызову некоторой операции при выполнении операций модификации, удаления, создания версии, перемещения объекта из общей базы данных в частную базу данных (check -out ) или наоборот (check -in ). По умолчанию выполнение операции оповещения приводит к отправке электронной почты привилегированному пользователю (администратору системы), но допускается замена поведения этой операции.
Допускается создание временной, рабочей или “выпускной” версии объекта. Для динамического или статического связывания разных версий поддерживается иерархия происхождения версий. При использовании динамического связывания версий иерархия автоматически модифицируется при создании новых версий.
Безопасность данных обеспечивается на основе механизма авторизации доступа, в котором конкретная привилегия (доступ по чтению, доступ по записи или создание) предоставляется роли, за которой может стоять один пользователь или группа пользователей. Привилегии могут быть подсоединены к базам данных, классам, экстентам, объектам, операциям и свойствам.
Имеется авторизация по умолчанию, которая подразумевается для любой роли и может быть дополнена явной авторизацией, положительной (с добавлением привилегий) или отрицательной (с изъятием привилегии).
При использовании C ++ стабильность достигается путем доступа к библиотеке классов, поддерживающих стабильность. В CLOS (Common Lisp Object System ) обеспечивается метакласс стабильности. Стабильные объекты должны быть экземплярами классов, являющихся экземплярами этого метакласса. Кроме того, можно указать, что некоторые свойства стабильного класса являются недолговечными.
В ITASCA поддерживаются C , C ++, Smalltalk , CLOS . Акцент делается на возможности динамического изменения схемы без остановки действия системы и без потребности в массовой повторной компиляции и редактирования связей. Доступ к программам на каждом из языков производится через функциональный API . В случае использования C ++ автоматически создается файл заголовков, который сливается с исходными файлами программного кода при генерации приложения.
Собственный механизм запросов ITASCA позволяет запрашивать данные в частной базе данных, общей базе данных или сразу в обеих базах данных. Для повышения производительности применяются оптимизация запросов и методы распараллеливания.
Язык определения объектов ODL
ODL является языком определения данных для объектной модели ODMG 27. ODL используется исключительно для описания интерфейсов типов приложения, а не для программирования реализации. Это не язык программирования, а всего лишь язык описания схем баз данных.
“Программа” на языке ODL – это набор определений типов, констант, исключительных ситуаций, интерфейсов типов и модулей. Не углубляясь в детали и не приводя синтаксических правил, остановимся на наиболее интересных (с точки зрения автора этой статьи) особенностях ODL.
Язык обеспечивает исключительно мощные возможности для определения литеральных типов. С точки зрения автора, наиболее интересны типы коллекций. Можно определить четыре разновидности типов коллекций. Типы категории set – это обычные типы множеств. Типы категории bag – эти типы мультимножеств (в значениях которых допускается наличие элементов-дубликатов). Значениями типов категории list являются упорядоченные списки значений (среди них допускаются дубликаты). Наконец, значениями типы dictionary являются множества пар <ключ, значение> , причем все ключи в этих парах должны быть различными. Определения типов имеют рекурсивную природу. Например, можно определить тип множества структур, элементами которых будут являться списки мультимножеств и т.д.
Синтаксические правила, относящиеся к определению объектных типов, требуют достаточно подробных разъяснений. К сожалению, в стандарте ODMG 3.0 этих разъяснений явно недостаточно. Поэтому дальнейший текст этого пункта является некоторым домыслом автора этой статьи, который логичен, но не обязательно соответствует истинным взглядам авторов стандарта (проверить это не представляется возможным).28
Во-первых, объектный тип можно определить с помощью двух разных синтаксических конструкций языка ODL – interface и class
29. Определение класса отличается от определения интерфейса наличием двух необязательных разделов: extends и type _ property _ list . В действительности, наиболее важным отличием класса от интерфейса является возможность наличия второго из этих разделов.
В списке свойств30 могут присутствовать элементы extent и key . В спецификации модели данных ODMG 3.0 (хотя это и не отражается явно в синтаксисе ODL ) говорится, что для каждого класса может быть определен только один экстент, являющийся множеством всех объектов этого класса, которые после создания должны сохраняться в базе данных.31
Ключ – это набор свойств объектного класса, однозначно идентифицирующий состояние каждого объекта, входящего в экстент класса (это аналог возможного ключа реляционной модели данных). Для класса может быть объявлено несколько ключей, а может не быть объявлено ни одного ключа даже при наличии определения экстента. В последнем случае в экстенте класса могут существовать разные объекты с одним и тем же состоянием.32
Рис. 2.3. Пример иерархии объектных типов и их экстентов
Далее, хотя и интерфейсы, и классы являются средствами определения объектных типов, между ними проводится жесткое различие. Допускается создание объектов только тех объектных типов, которые определены как классы. Объектные типы, определенные как интерфейсы, могут использоваться только для порождения новых объектных типов (интерфейсов и классов) на основании (вообще говоря) множественного наследования. Классы могут определяться на основе (вообще говоря) множественного наследования интерфейсов и одиночного наследования классов.
Механизм наследования от интерфейсов называется в ODMG наследованием IS - A, а механизм наследования от классов – extends . Прежде чем попытаться пояснить этот подход, приведем пример графа наследования интерфейсов и классов, в котором также показывается место существующих экстентов и объектов (рис. 2.3).
На рис. 2.3 “жирными” стрелками показаны связи объектных типов по наследованию IS - A . Обычные стрелки показывают связи по наследованию extends . Пунктирные стрелки соответствуют связям экстентов и соответствующих классов. Обратите внимание, что на этом рисунке у каждого из классов, входящих в иерархию, определен свой собственный экстент.
Как демонстрирует рисунок, в модели ODMG поддерживается семантика включения, означающая, что экстент любого подкласса является подмножеством экстента любого своего суперкласса (прямого или косвенного). Если у некоторого подкласса свой собственный экстент не определен, то с объектами этого подкласса можно работать только через экстент какого-либо суперкласса. Стандарт не требует обязательного определения экстента. В этом случае ответственность на поддержку работы с множествами объектов ложится на прикладного программиста (для этого можно использовать типы коллекций).
Итак, при порождении подкласса путем наследования extends от некоторого суперкласса подкласс наследует экстент и набор ключей суперкласса. Как мы уже заметили, для подкласса можно определить свой собственный экстент. Что же касается возможности переопределения ключей, то в стандарте отсутствуют явные указания о возможности или невозможности этого действия. Однако очевидно, что если бы было разрешено полное переопределение набора ключей для экстента подкласса, то это противоречило бы семантике включения. По мнению автора данной статьи, по этому поводу можно трактовать ODL одним из двух способов:
(1) Если в некотором подклассе определен набор ключей, то в любом его подклассе определение ключей запрещается.
(2) Если в некотором подклассе определен набор ключей, то определение ключей в любом его подклассе приводит к расширению для этого подкласса набора ключей суперкласса.
Теперь немного поговорим о связях. Связи определяются между объектными типами. В модели ODMG поддерживаются только бинарные связи, т.е. связи между двумя типами. Связи могут быть разновидностей “один-к-одному”, “один-ко-многим” и “многие-ко-многим” в зависимости от того, сколько экземпляров соответствующего объектного типа может участвовать в связи.
Связи явно определяются путем указания путей обхода (traversal paths ). Пути обхода указываются парами, по одному пути для каждого направления обхода связи33. Например, в базе данных “служащие-отделы-проекты” служащий работает (works ) в одном отделе, а отдел состоит (consists of ) множества служащих.
Тогда путь обхода consists _ of должен быть определен в объектном типе DEPT , а путь обхода works – в типе EMP . Тот факт, что пути обхода относятся к одной связи, указывается в разделе inverse обоих объявлений пути обхода. В нашем случае определения типов DEPT и EMP могли бы выглядеть следующим образом:
class DEPT {
...
relationship set <EMP> consists_of
inverse EMP :: works
... }
class EMP {
...
relationship DEPT works
inverse DEPT :: consists_of
... }
Как видно, это связь “один-ко-многим”. Путь обходаconsists _ of ассоциирует экземпляр типа DEPT со множеством экземпляров типа EMP , а путь обхода works ассоциирует экземпляр типа EMP с экземпляром типа DEPT . Пути обхода, ведущие к коллекциям объектов, могут быть упорядоченными или неупорядоченными в зависимости от вида коллекции, указанному в объявлении пути обхода. В приведенном выше примере consists _ of является неупорядоченным путем обхода.
В ООСУБД, соответствующей стандарту ODMG , должна поддерживаться ссылочная целостность связей. Это означает, что при ликвидации любого объекта, участвующего в связи, должны ликвидироваться и все пути обхода, ведущие к этому объекту. Такой подход гарантирует, что приложения не смогут воспользоваться путями обхода, ведущими к несуществующим объектам.
Наконец, хотя это явно не отражено в синтаксисе языка ODL (по непонятным для меня причинам), наряду с набором генераторов литеральных типов коллекций set < b>t > , bag < t > , list < t > , array < t > и dictionary < t , v > поддерживается аналогичный набор генераторов объектных типов коллекций – Set < t > , Bag < t > ,List < t > , Array < t > и Dictionary < t , v > . В отличие от литералов-коллекций объекты-коллекции обладают объектными идентификаторами и свойством изменчивости. Во всех случаях требуется, чтобы все элементы коллекции были одного типа, литерального или объектного. И для литеральных, и для объектных коллекций поддерживается возможность итерации
коллекции с перебором элементов коллекции либо в порядке, определяемом системой (для множеств и мультимножеств), либо в порядке, предполагаемом видом коллекции (для списков, массивов и словарей).
Краткая характеристика языка запросов OQL
В кратком и неформальном описании языка мы будем по возможности строго следовать манере и последовательности изложения, принятым в стандарте ODMG 3.0, меняя только примеры.
Разработчики языка основывались на следующих основных принципах:
OQL опирается на объектную модель ODMG.
OQL очень близок к SQL /92. Расширения относятся к объектно-ориентированным понятиям, таким как сложные объекты, объектные идентификаторы, путевые выражения, полиморфизм, вызов операций и отложенное связывание.
В OQL обеспечиваются высокоуровневые примитивы для работы с множествами объектов, но, кроме того, имеются настолько же эффективные примитивы для работы со структурами, списками и массивами.
OQLявляется функциональным языком, допускающим неограниченную компонируемость операций, если операнды не выходят на пределы системы типов. Это является следствием того факта, что результат любого запроса обладает типом, принадлежащим к модели типов ODMG, и поэтому к результату запроса может быть применен новый запрос.
OQL не является вычислительно полным языком. Он представляет собой простой язык запросов.
Операторы языка OQL могут вызываться из любого языка программирования, для которого в стандарте ODMG определены правила связывания. И наоборот, в запросах OQL могут присутствовать вызовы операций, запрограммированных на этих языках.
В OQL не определяются явные операции обновления, а используются вызовы операций, определенных в объектах для целей обновления.
В OQL обеспечивается декларативный доступ к объектам. По этой причине OQL -запросы могут быть легко оптимизированы.
Можно легко определить формальную семантику OQL.
Множественное наследование
Обеспечение или не обеспечение системой множественного наследования не является обязательным. Поскольку сообщество специалистов в области объектно-ориентированного подхода еще не достигло согласия относительно множественного наследования13, обеспечение такого наследования считается необязательным. В случае принятия решения о поддержке множественного наследования предстоит выбор из множества возможных решений проблемы разрешения конфликтов.
Немного истории
В начале 80-х гг. осознание полезности объектно-ориентированного подхода применительно к логической организации баз данных привело к тому, что многие исследователи приступили к созданию ООСУБД. В ранних проектах ООСУБД участвовали группы из университетов и исследовательских институтов, ведущих компьютерных компаний и небольших начинающих компаний.
Университетские исследовательские группы внесли огромный вклад в развитие технологии баз данных, и не только в области реляционных систем. Многие университетские исследователи с энтузиазмом приняли объектно-ориентированный подход, особенно в применении к области человеко-машинных взаимодействий. К наиболее успешным проектам, в которых производились исследования с целью объединения объектно-ориентированного подхода с технологией баз данных, можно отнести следующие:
Encore в Брауновском университете (Broun University );
Cactis в Колорадском университете (University of Colorado at Boulder);
Thor в Массачусетском технологическом институте (MIT );
Exodus в Висконсинском университете (University of Wisconsin );
Pisa в университетах Глазго и Св. Эндрю (Universities of Glasgo and St. Andrew).
Среди исследовательских институтов, в которых существовали мощные группы, ориентированные на исследования в области объектно-ориентированных баз данных, входили OGI (Oregon Graduate Institute ), MCC (Microelectronics and Computer Technology Corporation ) и французский исследовательский центр INRIA . На базе исследований OGI была создана ООСУБД Gemstone ; исследования, проводившиеся в MCC , привели к созданию ООСУБД Itasca и UniSQL ; в результате исследовательского проекта Altair , выполнявшегося в INRIA , появилась ООСУБД O 2.
Среди наиболее значительных прототипов ООСУБД, созданных в результате исследований, которые проводились в ведущих компьютерных компаниях, можно выделить систему IRIS компании Hewlett -Packard и систему Trellis компании DEC . Идеи и методы, заложенные в этих проектах, были впоследствии использованы в большинстве коммерческих ООСУБД.
Тем не менее, руководители крупных компаний решили не производить коммерческие ООСУБД самостоятельно, а предоставить эту возможность начинающим компаниям.
Первыми компаниями, выпустившими на рынок ООСУБД в виде законченных продуктов, были следующие компании:
Grapael сООСУБД G-Base (1986 г);
Servio-Logic сООСУБД Gemstone (1987 г.);
Symbolics сООСУБД Statice (1988 г.);
Ontologic Ltd. сООСУБД Vbase (1988 г.).
Ко всем ранним реализациям ООСУБД применительны следующие замечания.
Системы были почти неприменимы для практического использования, поскольку они очень медленно работали, поддерживали только однопользовательский режим работы и были крайне ненадежны. В них не поддерживались распределенные данные, безопасность и возможность восстановления после сбоев. Почти во всех системах отсутствовали развитые механизмы формулировки запросов. При построении пользовательских интерфейсов не использовались даже уже имевшиеся результаты, полученные группами из области человеко-машинных взаимодействий.
Разработчики практически всех систем полностью игнорировали язык C ++, поскольку считалось, что применение этого языка в контексте ООСУБД вызывает серьезные проблемы. В системах G -Base и Statice использовался Lisp ; Gemstone опиралась на Smalltalk ; для Vbase были разработаны собственные языки определения данных (TDL ) и манипулирования данными (COP ). В исследовательских группах также предпочитали не опираться на C ++, а разрабатывать новые языки, в большей степени соответствующие направлению исследований. Среди отрицательных последствий игнорирования C ++ было то, что пользователей заставляли изучать новый язык; они вынуждались одновременно использовать два языка; отсутствие поддержки C ++ ограничивало рынок ООСУБД.
Новые компании Objectivity , Object Design и Versant , образованные в конце 80-х, ориентировались на создание ООСУБД, которые опирались бы на C ++. Компания Ontologic отказалась от развития Vbase и переключилась на разработку системы ONTOS , основанной на C ++.
В Европе были образованы компании O 2Technology и BKS Software . Задачей первой компании было создание коммерческой ООСУБД O2 49 на основе результатов проекта Altair . BKS начала разработку системы POET . В 90-е годы для реализации коммерческих проектов, основанных на результатах MCC , были образованы компании UniSQL 50 и Itasca .
К концу 90-х существовало около десяти компаний, производящих коммерческие продукты, позиционируемые на рынке как ООСУБД. Каждый продукт обладал индивидуальными особенностями, частично определяемыми жизненным опытом разработчиков, но большей частью проистекающими из требований клиентов компании. Далее в этом подразделе мы кратко охарактеризуем наиболее известные коммерческие ООСУБД, а в заключение подраздела опишем современное состояние дел в области ООСУБД (которое, по мнению автора, является совсем не блестящим).
Необязательные возможности: конфетки
Под этим заголовком собраны возможности, которые улучшают систему, но не являются обязательными для того, чтобы система была объектно-ориентированной системой баз данных. Некоторые из этих возможностей являются объектно-ориентированными по своей природе (например, множественное наследование12). Они отнесены к категории необязательных возможностей, потому что не входят в набор ключевых требований, хотя и делают систему более объектно-ориентированной.
Другие возможности являются просто возможностями систем баз данных (например, управление проектными транзакциями). Эти характеристики обычно улучшают функциональные возможности систем баз данных, но не относятся к ключевым требованиям, предъявляемым к таким системам, и они не связаны с аспектом объектной ориентированности. В действительности, многие из этих возможностей предназначены для обслуживания “новых” приложений (CAD /CAM , CASE , офисная автоматизация и т.д.) и являются более ориентированными на приложения, чем на технологии. Поскольку многие системы объектно-ориентированных баз данных нацелены на эти новые приложения, то существует некоторая путаница между этими возможностями и объектно-ориентированной природой системы.
Неопределенные значения
Поддержка неопределенных значений является одной из наиболее запутанных проблем современной технологии баз данных. Автору данной статьи неизвестно какое-либо удовлетворительное решение проблемы. ODMG тщательно обходит проблему неопределенных значений и пытается свести ее к проблеме неопределенных идентификаторов объектов.39 Опишем подход ODMG с минимальными комментариями.
Результатом выборки свойства объекта с пустым идентификатором является специальное значение UNDEFINED . В OQL UNDEFINED считается специальным литеральным значением, входящим во множество значений любого литерального или объектного типа.40
Правила обращения со значением UNDEFINED состоят в следующем:
Результатом операции is _ undefined ( UNDEFINED ) является логическое значение true . Результатом операции is _ defined ( UNDEFINED ) является логическое значение false .
Если при вычислении предиката раздела WHERE OQL -запроса получается значение UNDEFINED , то оно трактуется таким же образом, если бы результатом было значение false .
UNDEFINED является допустимым элементом любой явно или неявно конструируемой коллекции.41
UNDEFINED является допустимым выражением при вычислении агрегатной функции COUNT .42
Результатом любой другой операции, включающей хотя бы один операнд со значением UNDEFINED , является UNDEFINED . 43
Пример 2.11. Найти номера отделов всех сотрудников.
SELECT E.WORKS.DEPT_NO
FROM EMPLOYEES E
Результатом запроса будет мультимножество литералов, среди которых будет содержаться значение UNDEFINED для всех сотрудников, не прикрепленных к какому-либо отделу.
Пример 2.11. Найти всех сотрудников, прикрепленных к какому-либо отделу.
SELECT E
FROM EMPLOYEES E
WHERE is_defined (E.WORKS.DEPT_NO)
Такой же результат был бы выдан при выполнении запроса
SELECT E
FROM EMPLOYEES E
WHERE E.WORKS != nil
Объектно-ориентированные базы данных в стандарте ODMG
Первый манифест формально являлся всего лишь статьей, представленной на Конференцию по объектно-ориентированным и дедуктивным базам данных группой частных лиц. Как вы могли видеть в предыдущем подразделе, требования Манифеста были скорее эмоциональными, чем явно специфицированными. В 1991 г. был образован консорциум ODMG (тогда эта аббревиатура раскрывалась как Object Database Management Group , но впоследствии приобрела более широкую трактовку – Object Data Management Group ). Консорциум ODMG тесно связан с гораздо более многочисленным консорциумом OMG (Object Management Group ), который был образован двумя годами раньше. Основной исходной целью ODMG была выработка промышленного стандарта объектно-ориентированных баз данных (общей модели). За основу была принята базовая объектная модель OMG COM (Core Object Model ). В течение более чем десятилетнего существования ODMG опубликовала три базовых версии стандарта, последняя из которых называется ODMG 3.0 [5]. 16
Забавно, что хотя ODMG (по мнению автора) вышла из OMG , в последние годы некоторые стандарты OMG опираются на объектную модель ODMG . В частности, на модель ODMG опирается спецификация языка OCL (Object Constraint Language ), являющаяся частью общей спецификации языка UML 1.4 (и UML 2.0) [7]. В этой статье мы не ставим цель провести детальное сопоставление подходов OMG и ODMG и отсылаем заинтересованных читателей к Энциклопедии Когаловского [6] и материалам сайтов этих консорциумов [7-8]. Мы ограничимся кратким изложением основных идей, содержащихся в стандарте ODMG -3.
Объектно-ориентированные СУБД
В последнем подразделе этого раздела мы обсудим специфические черты наиболее известных и распространенных в мире ООСУБД. Трудно гарантировать, что это обсуждение полностью соответствует текущему положению дел, поскольку ситуация изменяется очень быстро, и то, что пишется сегодня и полностью отвечает истинному положению дел, может оказаться не совсем (или совсем не) верным завтра. Но, тем не менее, мы считаем, что такой подраздел должен присутствовать в разделе про Первый манифест, чтобы показать читателям реальное (или близкое к реальному) состояние дел в соответствующей области информационной технологии.
Объектные и литеральные типы
В модели ODMG база данных представляет собой коллекцию различимых значений (denotable values ) двух видов – объекты и литералы. Объекты обладают свойствами идентифицируемости и индивидуального существования, а литералы являются компонентами объектов. Модель данных содержит конструкции для спецификации объектных и литеральных типов. Объектные типы существуют в иерархии объектных типов; литеральные типы похожи на типы, характерные для обычных языков программирования (например, С или Pascal ). В модели ODMG не используется термин класс. Единственная классификационная конструкция называется типом, и типы описывают как объекты, так и литералы. То, что называлось классом в Первом манифесте, в ODMG называется объектным типом.
В модели поддерживается ряд литеральных типов – базовые скалярные числовые типы, символьные и булевские типы (атомарные литералы), конструируемые типы литеральных записей (структур) и коллекций. Конструируемые литеральные типы могут основываться на любом литеральном или объектном типе, но считаются неизменчивыми. Даты и время строятся как литеральные структуры. Подробнее о литеральных типах см. в следующем подразделе.
Объектный тип состоит из интерфейса и одной или нескольких реализаций.25 Интерфейс описывает внешний вид типа: какими свойствами он обладает, какие в нем доступны операции и каковы параметры у этих операций.26 В реализации определяются структуры данных, реализующие свойства, и программный код, реализующий операции. Интерфейс составляет общедоступную (public ) часть типа, а в реализации при необходимости могут вводиться дополнительные частные (private ) свойства и операции. Все объектные типы (системные или определяемые пользователем) образуют решетку (lattice ) типов, в корне которой находится предопределенный объектный тип Object . Чтобы не объяснять подробно, что такое решетка, приведем пример графа, являющегося решеткой (рис. 2.2).
Рис. 2.2. Пример ориентированного графа, являющегося решеткой
Поскольку для определения реализации объектного типа требуется использовать один из языков OML , которые мы в этой статье не обсуждаем, ограничимся рассмотрением интерфейсной части типа.
Интерфейс объектного типа состоит их следующих компонентов:
имя;
набор супертипов;
имя поддерживаемого системой экстента;
один или более ключей для ассоциативного доступа;
набор атрибутов,каждый из которых может быть объектом или литеральным значением;
набор связей, каждая из которых указывает на некоторый другой объект;
набор операций.
Атрибуты и связи совместно называются свойствами, а свойства и операции совместно называются характеристиками объектного типа (или объектов данного типа).
Точно так же, как имеются атомарные и конструируемые литеральные типы, существуют атомарные и конструируемые объектные типы. В стандарте ODMG 3.0 говорится, что атомарными объектными типа являются только типы, определяемые пользователями (см. ниже).. Конструируемые объектные типы включают структурные типы и набор типов коллекций.
Объекты и литералы
Как утверждалось в Первом манифесте, одним из важнейших отличий объектов от значений является наличие у объекта уникального идентификатора (объекты обладают свойством идентифицируемости). Накладные расходы, требуемые для обращения к объекту по его идентификатору с целью получения доступа к базовым значениям данных, могут весьма сильно замедлить работу приложений. Поэтому в модели ODMG допускается описание всех данных в терминах объектов и использование традиционного вида значений, которые в модели называются литеральными значениями. Таким образом, возраст человека может задаваться целочисленным литералом, а не объектом, имеющим свойство21 возраст. В этом случае значение возраста будет сохраняться как часть структуры данных объекта человек, а не в отдельном объекте. Это, в частности, означает, что объект может входить в состав нескольких других объектов, а литерал – нет. Схема базы данных в модели ODMG главным образом состоит из набора объектных типов, но компонентами этих типов могут быть типы литеральных значений.
Другим понятием, используемым для различения объектов и литералов, является понятие изменчивости (mutability ). Предположим, например, что данные о человеке составляют структуру <имя, возраст, адрес_проживания> . Тогда возможны два варианта хранения этих данных:
Если человек представляется в виде объекта, то компоненты описывающей его структуры данных могут изменяться (например, может изменяться адрес), но объект (человек) остается тем же самым (поскольку объектный идентификатор не изменяется). Тем самым, объекты обладают свойством изменчивости.
Если же данные о человеке сохраняются в виде литеральной структуры, и один из компонентов этой структуры изменяется, то вся структура трактуется как новое значение. Если данные о человеке не должны изменяться, то не может изменяться ни один элемент структуры, и она является неизменчивым литералом.22
Другими словами, объект идентифицируется своим объектным идентификатором (OID – Object Identifier ), который полностью отделен от значений компонентов объекта, а литерал полностью идентифицируется значениями своих компонентов.
Объекты как результаты запросов
В примерах предыдущего пункта результатами запросов являлись литеральные значения, не обладающие объектными идентификаторами. Если ввести следующие определения объектных типов:
typedef Set <interval> ages;
class persinfo {
attribute string <20> n;
attribute date b; };
typedef Bag <persinfo > info;
то можно сформулировать следующие запросы.
Пример 2.5
ages ( SELECT DISTINCT E.age
FROM EMPLOYEES E
WHERE E.EMP_SAL > 20000.00 )
Окончательным результатом этого запроса является объект-множество, включающий литеральные значения типа interval . 37
Пример 2.6
info ( SELECT persinfo (n: E.EMP_NAME, b: E.EMP_BDATE)
FROM EMPLOYEES E
WHERE E.EMP_SAL > 20000.00 )
В этом примере по литеральным значениям имени и даты рождения каждого служащего, размер зарплаты которого превышает 20000 руб., конструируется объект типа persinfo , а на основе литерального мультимножества этих объектов конструируется объект-мультимножество типа info .
В совокупности результатом допустимых в OQL выражений запросов могут являться:
коллекция объектов;
индивидуальный объект;
коллекция литеральных значений;
индивидуальное литеральное значение.
Обязательные свойства: золотые правила
Система объектно-ориентированных баз данных должна удовлетворять двум критериям: она должна быть СУБД и при этом являться объектно-ориентированной системой, т.е. в максимально возможной степени находиться на уровне современных объектно-ориентированных языков программирования. Первый критерий включает пять свойств: стабильность, управление вторичной памятью, параллелизм, восстанавливаемость и средства обеспечения незапланированных (ad hoc ) запросов. Второй опирается на восемь свойств: сложные объекты, идентифицируемость объектов, инкапсуляция, типы или классы, наследование, перекрытие методов совместно с поздним связыванием, расширяемость и вычислительная полнота.
Objectivity /DB
Компания Objectivity (http://www.objectivity.com ) была образована в 1988 г. В 1990 г. была выпущена первая версия системы, которая представляла собой распределенную СУБД, основанную на использовании объектной технологии, высокопропускных локальных сетей и симметричных мультипроцессоров. Система работает на всех основных UNIX -платформах и в среде Windows .
Система основана на клиент-серверной архитектуре, в которой единицей обмена между сервером и клиентом является страница базы данных. Тем самым многие системные функции, включая кэширование, поиск объектов и преобразование их форматов, выполняются на стороне клиента. Объектные идентификаторы представляются в 64-разрядном формате, что обеспечивает потенциальную возможность работы со сверхбольшими базами данных.
Поддерживается четырехуровневая структура хранения данных. Объекты содержатся в контейнерах, каждый из которых представляет собой часть локальной базы данных. Локальные же базы данных могут комбинироваться в федеративную (распределенную) базу данных. Надежность хранения данных поддерживается механизмом репликации.
Обеспечивается возможность изменения классов и автоматического образования новых версий существующих объектов. Поддерживается механизм управления иерархиями версий объектов.
Допускаются как короткие, так и долгие транзакции. Управление короткими транзакциями основано на синхронизационных блокировках и распознавании тупиков. Долгие транзакции и коллективная работа с базами данных основаны на многоверсионности объектов и механизме check -in /check -out .
В системе поддерживаются языки C ++ и Smalltalk , но способы использования языков сильно различаются. Это относится и к механизмам стабильности, и к средствам определения данных. В среде C ++ стабильными являются объекты всех классов, являющихся наследниками специального системного класса. В среде Smalltalk стабильными являются все объекты, достижимые от именованных корневых объектов-словарей. Соответственно, в Smalltalk для удаления объектов используется механизм сборки мусора, а в C ++ – явные операции.
Естественно, базы данных, управляемые Objectivity /DB , основаны на одной объектной модели. Эта модель достаточно близка к модели ODMG и, в частности, включает возможность определения двунаправленных связей. Поддерживается возможность управления составными объектами с распространением на подобъекты операции удаления. Однако способы определения данных в средах C ++ и Smalltalk различаются.
В C ++ включено специальное расширение языка, предназначенное для определения данных. Соответствующие конструкции обрабатываются специальным препроцессором, который генерирует код C ++, содержащий соответствующие обращения к СУБД. В среде Smalltalk схема базы данных определяется как набор классов Smalltalk . Другими словами, при использовании Smalltalk приложения, работающие с базами данных Objectivity /DB , организуются более прозрачным образом, чем в случае C ++.
Имеется поддержка языка SQL /89 и, частично, SQL /92. Реляционный доступ к базам данных, управляемых Objectivity /DB , возможен через интерактивный SQL -ориентированный интерфейс, через имеющийся драйвер ODBC и через API .
ObjectStore
Компания Object Design была основана в 1988 г. с экстренной целью разработать и вывести на рынок ООСУБД, которую стали называть ObjectStore . В конце 90-х у Object Design установились тесные партнерские отношения с IBM , что позволило привлечь к ObjectStore тысячи разработчиков приложений. На основе технологии ObjectStore компанией был разработана одна из первых коммерческих СУБД – Excelon , ориентированная на управление XML -данными. С начала 2003 г. компания является подразделением компании Progress Software (http://www.objectstore.net).
ООСУБД ObjectStore основана на архитектуре клиент-сервер, в которой каждый сервер отвечает за регулирование доступа к хранилищу объектов и управляет журнализацией обновлений, блокировками, установкой контрольных точек, разрешением конфликтов по данным, резервированием данных и восстановлением базы данных после сбоев. Каждый сервер поддерживает множество клиентов. В клиентском процессе используется представление данных более высокого уровня, и клиентская часть ObjectStore отвечает за управление коллекциями, выполнение запросов и управление транзакциями.
Серверная часть спроектирована в расчете на использование механизма отображения виртуальной памяти, которая распространяется на всю сеть и может охватывать несколько серверов. Извлекаемые из базы данных объекты могут объединяться в пакеты для передачи по сети, что позволяет снизить объем сетевого трафика. Для сокращения времени доступа в серверах используется техника кластеризации. На каждой клиентской части имеется локальный кэш, в котором сохраняются используемые объекты. Когда объект перемещается в адресное пространство клиента, ссылки на него перерабатываются таким образом, что для каждого к объекту доступа достаточно одной команды компьютера.
Управление мультидоступом основано на использовании прозрачного для пользователя механизма блокировок, включающего возможность блокирования по чтению и по записи. Поддерживаются разные уровни детализации (гранулированности) блокировок от уровня страниц внешней памяти базы данных до конфигураций (указываемых программистом групп объектов).
Надежность хранения данных обеспечивается за счет поддержания журнала произведенных изменений. Подсистема управления транзакциями отвечает за журнализацию всех произведенных изменений на основе протокола WAL (Write Agead Log – упреждающей записи в журнал). Дополнительно поддерживается архивный журнал, в котором авторизованный пользователь может произвести архивное копирование базы данных.
Имеется средство поддержки версий, которое обеспечивает возможность коллективной работы с базами данных на основе механизмов check -in /check -out . На этом подходе основывается поддержка долгих транзакций. Для каждой конфигурации объектов можно создать историю версий, независимую от типов объектов.
В ObjectStore стабильность хранения объектов поддерживается за счет наличия именованных корневых стабильных объектов класса база данных. База данных создается с помощью вызова метода new этого класса. Имеются методы для открытия и закрытия базы данных. Кроме того, в классе содержатся методы для создания стабильных корневых объектов, обычно являющихся коллекциями, в которых размещаются стабильные объекты.
Поддерживаются языки C , C ++ и Smaltalk . Свойство стабильности обеспечивается за счет включения в библиотеку классов специальных системных классов. Имеются классы, поддерживающие коллекции – списки, множества, мультимножества и массивы. Методы этих классов поддерживают выборку объектов из коллекций, вставку и удаление объектов.
Поддерживаются шлюзовые объекты, поддерживающие доступ к реляционным данным, а также инструментальные средства для отображения реляционной схемы в эквивалентное объектно-ориентированное представление. Таким образом, с реляционными базами данных можно работать в интерфейсе ODBC на основе SQL или в собственном интерфейсе ObjectStore .
Однородность
Ведутся жаркие споры о степени однородности таких систем. Является ли тип объектом? Является ли метод объектом? Следует ли эти три понятия рассматривать отдельно? Эту проблему можно рассматривать на трех разных уровнях: уровне реализации, уровне языка программирования и уровне интерфейса.
На уровне реализации необходимо решить, будет ли информация о типе храниться как объект или будет реализована некоторая специализированная система. Это тот же самый вопрос, с которым сталкиваются проектировщики систем реляционных баз данных при принятии решения о том, как следует хранить схему – в виде таблицы или некоторым специальным образом. Решение следует принимать с учетом эффективности и простоты реализации. Какое бы ни было принято решение, оно не зависит от решения, принимаемого на более высоком уровне. Что касается объектно-ориентированных систем, то разногласия по поводу того, являются ли типы объектами, сохранились до сих пор. Правильнее сказать, что появилась некоторая каноническая точка зрения (где типы и классы объектами не являются, но сохраняется позиция однородности). По отношению к стандартным SQL -ориентированным базам данных уже не существует сомнений относительно методов сохранения схемы базы данных – в стандарте SQL , начиная с SQL /92, специфицирована структура таблиц (точнее, представлений), описывающих схему базы данных (информационной схемы в терминах SQL ).
На уровне языка программирования вопрос состоит в том, являются ли типы сущностями первого сорта в семантике языка. Споры ведутся главным образом вокруг этого вопроса. По-видимому, имеются различные стили однородности (синтаксический и семантический). Полная однородность на этом уровне также не согласуется со статической проверкой типов. Скорее, победил синтаксический стиль однородности. Как мы уже отмечали, во многих случаях допускаются операции над типами, но это операции времени компиляции (что-то вроде очень развитых средств макрогенерации).
Наконец, на уровне интерфейса требуется принять еще одно независимое решение. Типы, объекты и методы могут быть представлены для пользователя как однородные, если даже в семантике языка программирования они предстают как различные по своей природе понятия. Обратно, они могут быть представлены для пользователя как различные сущности, хотя язык программирования не делает между ними различия. Это решение следует принимать с учетом человеческого фактора. И здесь однородность не получилась. В языках спецификации объектных интерфейсов четко разделяются типы, объекты и методы.
Открытые возможности
Любая система, удовлетворяющая правилам с первого по тринадцатое, заслуживает названия ООСБД. При проектировании такой системы все равно еще остаются возможности выбора. Это степени свободы людей, реализующих ООСБД. Эти характеристики отличаются от обязательных в том смысле, что относительно них научное сообщество еще не достигло согласия. Они отличаются от необязательных возможностей тем, что непонятно, какая из альтернатив является более, а какая менее объектно-ориентированной.
Парадигма программирования
Авторы Первого манифеста не видят причины, по которой одной парадигме программирования следует отдать предпочтение перед другой. В качестве парадигмы программирования можно выбрать стиль логического программирования, стиль функционального программирования или стиль императивного программирования. Другим решением может быть независимость системы от стиля программирования и поддержка нескольких парадигм программирования.
Параллелизм
Что касается управления параллельным10 взаимодействием с системой нескольких пользователей, то должны обеспечиваться услуги того же уровня, который предоставляют современные системы баз данных. Система должна обеспечивать гармоническое сосуществование пользователей, одновременно работающих с базой данных. Поэтому должно поддерживаться стандартное понятие атомарности последовательности операций и управляемого совместного доступа. По крайней мере, должна обеспечиваться сериализуемость операций, хотя могут быть и менее жесткие альтернативы.
Перекрытие, перегрузка и позднее связывание
Имеются случаи, когда желательно иметь одно и то же имя для различных операций. Рассмотрим, например, операцию визуализации: она принимает на входе объект и отображает его на экране. В зависимости от типа объекта используются разные механизмы отображения. Если объект является изображением, то желательно, чтобы оно действительно появилось на экране. Если объект является человеком, то желательно, чтобы в том или ином виде был отображен описывающий человека кортеж. Наконец, если объект является графом, то желательно получить графическое представление. Рассмотрим теперь задачу отображения множества объектов, типы элементов которого не известны во время компиляции.
В приложениях, опирающихся на традиционные системы, потребовалось бы три операции: “отобразить растровое изображение”, “отобразить объект типа человек” и “отобразить граф”. В программе проверялся бы тип каждого объекта, входящего во множество, и использовалась бы соответствующая операция отображения. Для этого при программировании нужно знать все возможные типы объектов, которые могут входить в заданное множество, и соответствующие им операции отображения, и использовать их согласованным образом.
В объектно-ориентированной системе операция отображения определяется на уровне типа “объект” (наиболее общий тип в системе). Таким образом, операция отображения имеет единственное имя и может быть одинаковым образом применена к графам, людям и изображениям. Однако реализация операции переопределяется для каждого типа в соответствии с его особенностями (такое переопределение называется перекрытием – overlapping ). В результате три разные программы имеют одно имя “отобразить” (это называется перегрузкой – overloading ). Для отображения множества элементов мы просто применяем операцию отображения к каждому элементу, оставляя за системой выбор соответствующей реализации во время выполнения.
Здесь реализатор типов по-прежнему должен написать то же количество программ. Но прикладному программисту уже не нужно заботиться о трех различных программах.
Первый манифест
В Первом манифесте [1] была предпринята попытка дать определение системам объектно-ориентированных баз данных. Авторы стремились привести описание основных свойств и характеристик, которыми должна обладать система, претендующая на то, чтобы быть квалифицированной как система объектно-ориентированных баз данных. Насколько это удалось, судить вам.
Эти характеристики были разделены на три группы:
Обязательные, т. е. такие, которыми система должна обладать для того, чтобы ее можно было рассматривать как систему объектно-ориентированных баз данных. В число этих характеристик входят сложные объекты; идентифицируемость (identity) объектов; инкапсуляция, типы или классы; наследование; перегрузка методов совместно с поздним связыванием; расширяемость; вычислительная полнота; стабильность; управление вторичной памятью; параллелизм; восстанавливаемость; средства обеспечения незапланированных (ad hoc) запросов.
Необязательные, т.е., такие, которые могут быть добавлены к системе для ее улучшения, но обязательными не являются. К этим характеристикам относятся множественное наследование; проверка и вывод типов; распределенность; проектные транзакции; версии.
Открытые характеристики, которые проектировщик может реализовать по собственному усмотрению. В число этих характеристик входят используемая парадигма программирования, система представления, система типов и однородность.
Манифест рассматривался как отправная точка для дальнейшей дискуссии.
Полиморфизм
Как мы отмечали ранее в этом разделе, в объектной модели ODMG поддерживается семантика включения, т.е. в экстент суперкласса входят объекты экстентов всех его подклассов. Предположим, например, что мы определили класс PROGRAMMERS как наследника класса EMP через EXTENDS . Пусть для программистов меняется семантика метода HIGHER _ PAID (высокооплачиваемым программистом считается тот, кто получает более 30000 руб. в месяц). Тогда в классе PROGRAMMERS этот метод должен быть переопределен (с сохранением сигнатуры).
Понятно, что в соответствии с семантикой включения запрос из прим. 2.13 должен распространяться на всех служащих, включая программистов. Но если текущий объект E является объектом класса PROGRAMMERS , то к нему должен применяться переопределенный вариант метода HIGHER _ PAID . Тем самым, в OQL применятся отложенное связывание объектов и методов.
Еще одна возможность, связанная с полиморфизмом и поддерживающаяся в OQL , состоит в том, что пользователь может явно указать конкретный тип подкласса объектов коллекции, а система будет проверять правильность этого указания во время выполнения запроса. Предположим, что в классе PROGRAMMERS определен дополнительный атрибут favorite _ language , значение которого характеризуют “любимый” язык программирования каждого программиста. Кроме того, пусть известно, что в отделе 632 работают только программисты. Тогда возможен следующий запрос.
Пример 2.14. Получить названия любимых языков программирования сотрудников отдела 632.
SELECT DISTINCT ((PROGRAMMERS)E).favorite_language
FROM EMPLOYEES AS E
WHERE E.EMP_NO = 632
Если во время выполнения запроса будет обнаружено, что среди служащих отдела 632 имеются не только программисты, система зафиксирует ошибочную ситуацию.
Композиция операций
OQL является полностью функциональным языком. Если не нарушается система типов, то допускается произвольная композируемость операций. Этот подход отличается от подхода языка SQL , в котором правила композиции операций не являются ортогональными46.
Наличие полной ортогональности правил композиции в OQL позволяет не ограничивать мощность выражений и облегчить общее понимание языка, сохраняя возможность использования SQL -подобного синтаксиса при формулировке наиболее простых запросов.
Среди операций, которые поддерживаются в OQL и еще не упоминались в этом разделе, содержатся “множественные” операции union , intersect и except для всех видов коллекций; операции с кванторами for all и exists ; операции сортировки и группирования (sort и group by ); агрегатные операции count , sum , min , max и avg . Мы не будем подробно обсуждать эти операции47, но приведем пример достаточно сложного запроса, в котором некоторые из операций используются.
Пример 2.15. Найти название отдела, в котором работают служащие, средняя зарплата которых меньше средней зарплаты служащих любого другого отдела (для простоты предположим, что размер средней зарплаты служащих во всех отделах различается).
Будем строить запрос по шагам с использованием конструкции языка OQL define для вычисления промежуточных результатов.
Шаг 1. Построить множество объектов-служащих, для которых известен номер отдела.
define EMPLOYEES_D () AS
SELECT E FROM EMPLOYEES E
WHERE E.WORKS IS NOT nil
Шаг 2. Сгруппировать служащих с известными номерами отделов по номерам отделов и вычислить размер средней зарплаты для каждого отдела.
DEFINE DEPT_AVG_SAL () AS
SELECT DEPT_NO,
AVG_SAL : avg (SELECT X.E.EMP_SAL FROM PARTITION X )
FROM EMPLOYEES_D () E
GROUP BY DEPT_NO : E.DEPT_NO
Типомрезультатаэтогозапросаявляетсяbag < struct { integer DEPT_NO; decimal AVG_SAL } > . Операция group by расщепляет множество служащих на разделы (partitions ) в соответствии с критерием группирования (номеру отдела, в котором работает служащий). В разделе SELECT для каждого раздела вычисляется размер средней зарплаты сотрудников.
Шаг 3. Отсортировать полученное мультимножество по значениям атрибута AVG _ SAL .
DEFINE SORTED_DEPT_AVG_SAL () AS
SELECT S FROM DEPT_AVG_SAL () AS S ORDER BY S.AVG_SAL
Типомрезультатаявляетсяlist < struct { integer DEPT_NO; decimal AVG_SAL } > .
Шаг 4. Выбрать значение атрибута DEPT _ NO из элемента списка SORTED _ DEPT _ AVG _ SAL с наименьшим значением AVG _ SAL (этот элемент стоит в списке первым).
FIRST (SORTED_DEPT_AVG_SAL ()).DEPT_NO
Если собрать запрос целиком, то мы получим следующую конструкцию:
FIRST (SELECT DEPT_NO,
AVG_SAL : avg (SELECT X.E.EMP_SAL FROM PARTITION X )
FROM (SELECT E FROM EMPLOYEES E
WHERE E.WORKS IS NOT nil) AS E
GROUP BY DEPT_NO : E.DEPT_NO
ORDER BY AVG_SAL).DEPT_NO
Проектные транзакции
Для большинства новых приложений модель транзакций бизнес-ориентированной системы баз данных является неудовлетворительной: транзакции могут длиться слишком долго, и обычный критерий сериализуемости не является адекватным. Поэтому во многих ООСБД поддерживаются проектные транзакции (протяженные или вложенные).
Проверка и вывод типов
Вопрос о том, в какой степени система должна производить проверку типов во время компиляции, остается открытым, однако чем больше проверок во время компиляции, тем лучше. Оптимальной ситуацией является такая, когда успешно откомпилированная программа не может породить во время выполнения ошибки, связанные с несоответствием типов. Вопрос об объеме вывода типов также остается открытым на усмотрение системного проектировщика: чем больше, тем лучше; идеальной ситуацией является такая, в которой необходимо объявить только базовые типы, а система выводит временные типы.
Путевые выражения
Для навигации между подобъектами сложных объектов и по связям между разными объектами в OQL поддерживается специальный вид выражений, называемых путевыми (path expression ). Эти выражения определяются в так называемой точечной нотации (вместо операции “.” можно использовать и операцию “->”). Рассмотрим несколько простых примеров. Предположим, что в классах DEPT и EMP , кроме связи CONSISTS _ OF - WORKS определена еще и связь “один-к-одному” MANAGED _ BY - MANAGER _ OF :
class DEPT {
...
relationship EMP managed_by
inverse EMP :: manager_of
... }
class EMP {
...
relationship DEPT manager_of
inverse DEPT :: managed_by
... }
Пример 2.7. Для получения объекта типа EMP , соответствующего менеджеру отдела main _ department достаточно написать выражение
main_department.managed_by
Если же требуется получить имя менеджера отдела main _ department , то можно воспользоваться путевым выражением
main_department.managed_by.EMP_NAME
Пример 2.8. Получить имена всех сотрудников отдела main _ department.
Кажется, что запрос очень похож на предыдущий, и что для него годится выражение
main_department.consists_of.EMP_NAME
Но в данном случае мы имеем связь “один-ко-многим”, и хотя у каждого служащего имеется только одно имя, такие путевые выражения в OQL не допускаются. Правильной формулировкой запроса является следующая:
SELECT E.EMP_NAME
FROM main_department.consists_of AS E
Предикаты и логические операции
В спецификации OQL , как и в стандарте языка SQL , термин предикат обозначает условное выражение, которое может участвовать в запросе. Но семантика похожих на SQL конструкций языка OQL существенно отличается, что мы покажем в следующем примере.
Пример 2.9. Получить номера отделов и имена сотрудников отделов, с размером зарплаты, большим 10000 руб., работающих в отделах с числом сотрудников, большим 40 человек, и со средним размером зарплаты, большим 20000 руб.
SELECT STRUCT (DEPT_NO : D.DEPT_NO, EMP_NAME : E.EMP_NAME )
FROM DEPARTMENTS D,
D.CONSISTS_OF E
WHERE D.DEPT_EMP_NO > 40 AND
AVG (E.EMP_SAL) > 20000.00 AND
E.EMP_SAL > 10000.00
Как следует понимать семантику выполнения данного запроса? Образуется внешний цикл по просмотру объектов экстента DEPARTMENTS . Для каждого из этих объектов по связи CONSISTS _ OF образуется коллекция (в данном случае, множество) объектов, входящих в экстент EMPLOYEES . Тем самым, выполняется неявная факторизация (группирование) экстента EMPLOYEES , в которой инвариантом группы служащих является их общий отдел. По этому поводу в списке выборки и в условии выборки (предикате) разрешается использовать как свойства инварианта группы (в нашем случае, DEPT . DEPT _ NO и DEPT . DEPT _ EMP _ NO ) и индивидуальные свойства членов групп (в нашем случае, EMP . EMP _ NAME и EMP . EMP _ SAL ), так и “агрегатные” свойства группы в целом (в нашем случае, AVG ( EMP . EMP _ SAL ) ). Для каждой группы, образуемой во внешнем цикле, оцениваются условия, характеризующие группу в целом. В просмотр внутреннего цикла допускаются только те группы, для которых результатом вычисления условий “группы” было true . За каждым элементом “отобранной” группы сохраняются свойства ее объекта-инварианта.
Как видно даже из этого примера, предикаты раздела WHERE OQL -запросов могут представлять собой произвольно сложное булевское выражение, в котором простые условия связываются логическими операциями AND, OR и NOT. Очевидно, что этот набор операций является избыточным. Тем не менее, в OQL введены две дополнительные логические операции – ANDTHEN и ORELSE . Если X и Y являются логическими выражениями, то при вычислении выражения X ANDTHEN Y выражение Y вычисляется (и определяет общий результат) в том и только в том случае, когда результатом вычисления выражения X является true . Аналогично, при вычислении выражения X ORELSE Y выражение Y вычисляется (и определяет общий результат) в том и только в том случае, когда результатом вычисления выражения X является false . Другими словами, таблицы истинности операций ANDTHEN и ORELSE полностью совпадают с таблицами истинности операций AND и OR соответственно, но предписывается порядок вычислений.
Стандарт ODMG 3. 0 не обеспечивает подробного обоснования для введения этих операций, однако, по нашему мнению, это как-то связано с желанием остаться в рамках двухзначной логики при возможности наличия неопределенных значений. Вот пример запроса, в предикате которого можно сравнительно осмысленно использовать операцию ANDTHEN .
Пример 2.10. Получить имена служащих и номера их отделов для служащих, работающих в отделах с фондом заработной платы, размер которого превышает 1000000 руб.
SELECT STRUCT (name: E.EMP_NAME, dept: D.DEPT_NO)
FROM EMPLOYEES E,
E.WORKS D
WHERE E.WORKS != nil andthen
D.DEPT_TOTAL_SAL > 1000000.00
38
Кратко затронем тему запросов с соединениями. Должно быть понятно, что введение механизма связей в языки ODL и OQL главным образом связано с желанием отказаться от явных естественных соединений. Тем не менее, может возникнуть потребность в явных соединениях коллекций, объекты или литералы которых связываются по значениям. Вот простой пример.
Пример 2.10. Выбрать всех служащих, у которых имеются однофамильцы.
SELECT DISTINCT E
FROM EMPLOYEES E, EMPLOYEES E1
WHERE E != E1 AND E.EMP_NAME = E1.EMP_NAME
В результате будет образовано литеральное множество, элементами которого являются объекты типа EMP , для которых в экстенте EMPLOYEES имеется хотя бы один иной (с другим объектным идентификатором) объект, с тем же значением свойства EMP _ NAME . Понятно, что этот запрос и по виду, и по семантике выполнения является в чистом виде SQL -запросом (если заменить конструкцию E != E1 наE.EMP_NO <> E1.EMP_NO ).
Распределенность
Ясно, что эта характеристика является ортогональной к объектно-ориентированной природе системы. Система баз данных может быть как распределенной, так и нет.
Расширяемость
Система баз данных поставляется с набором предопределенных типов. Эти типы могут при желании использоваться программистами для написания приложений. Набор предопределенных типов должен быть расширяемым в том смысле, что должны иметься средства для определения новых типов и не должно быть различий в использовании системных и определенных пользователем типов. Конечно, способы поддержания системой системных и пользовательских типов могут значительно различаться, но эти различия должны быть невидимыми для приложения и прикладного программиста. Напомним, что определение типов включает определение операций этих типов. Заметим, что требование инкапсуляции подразумевает наличие механизма для определения новых типов. Требование расширяемости усиливает эту возможность, указывая, что вновь созданные типы должны иметь тот же статус, что и существующие. Однако не требуется, чтобы расширяемой была и совокупность конструкторов типов (кортежей, множеств, списков и т. д.).
Система представления
Система представления определяется набором атомарных типов и набором конструкторов. Хотя в числе Золотых правил указывается минимальный набор атомарных типов и конструкторов (элементарные типы языков программирования и конструкторы множеств, кортежей и списков), который должен быть доступен для описания представления объектов, этот набор может быть расширен множеством разнообразных способов.
Система типов
Остается свобода и в выборе способа формирования типов. Единственным средством формирования типов, наличия которого требуют авторы, является инкапсуляция. Возможны другие формирователи типов, такие как родовые типы, генераторы типов и т.д.
Сложные объекты
Сложные объекты строятся из более простых при помощи конструкторов. Простейшими объектами являются целые числа, символы, символьные строки произвольной длины, булевские переменные и числа с плавающей точкой (можно было бы добавить другие атомарные типы). Имеются различные конструкторы сложных объектов: конструкторы кортежей, множеств, мультимножеств, списков, массивов и т.д. Минимальный набор конструкторов, который должна иметь система, – это конструкторы множеств, списков и кортежей (множества обеспечивают естественный способ представления наборов объектов реального мира; кортежи представляют естественный способ представления свойств сущностей; списки и массивы сохраняют порядок, который имеет место в реальном мире).
Конструкторы объектов должны быть ортогональными, т.е. любой конструктор должен быть применим к любому объекту. (Конструкторы реляционной модели не являются ортогональными, потому что конструкция множества может быть применена только к кортежам, а конструкция кортежа – только к атомарным значениям.)
Для поддержки сложных объектов необходимы соответствующие операторы. То есть операции со сложным объектом должны транзитивно распространяться на все его компоненты. Примерами могут быть выборка или удаление сложного объекта целиком или создание “глубокой” копии (в отличие от “поверхностной” копии, в которой компоненты не копируются: в копии корня объекта указываются ссылки на компоненты копируемого объекта).
Средства обеспечения незапланированных запросов
Основной проблемой является обеспечение функциональности языка незапланированных (ad hoc ) запросов. Авторы Первого манифеста не призывают к тому, чтобы эта функциональность обязательно была реализована в виде языка запросов, а требуют только, чтобы была такая услуга существовала. Например, для обеспечения этой функциональной возможности вполне достаточно наличие графической программы просмотра. Услуга состоит в том, что пользователь может без затруднений сделать простой запрос к базе данных.11 Очевидной мерой являются, конечно, реляционные системы. Поэтому проверка наличия средства незапланированных запросов состоит в том, чтобы взять на пробу несколько реляционных запросов и проверить, можно ли их сформулировать с теми же затратами труда. Заметим, что это средство могло бы поддерживаться языком манипулирования данными или его подмножеством.
Средство обеспечения запросов должно удовлетворять следующим трем критериям:
Оно должно быть средством высокого уровня, т. е., пользователь должен иметь возможность кратко выразить нетривиальные запросы. Для этого средство формулирования должно быть достаточно декларативным, т. е., упор должен быть сделан на “что”, а не на “как”.
Оно должно быть эффективным. Для этого формулировка запросов должна допускать возможность оптимизации запросов.
Средство запросов не должно зависеть от приложения, т. е. оно должно работать с любой возможной базой данных. Это последнее требование устраняет потребность в специфических средствах обеспечения запросов для конкретных приложений и необходимость написания дополнительных операций для каждого определенного пользователем типа.
Стабильность
Это требование очевидно с точки зрения баз данных, но является новым с точки зрения языков программирования. Стабильность (persistence )9 означает возможность программиста обеспечить сохранность данных после завершения выполнения процесса с целью последующего использования в другом процессе. Свойство стабильности должно быть ортогональным к другим свойствам, т.е. для каждого объекта вне зависимости от его типа должна иметься возможность сделать его стабильным (без какой-либо явной переделки объекта). Стабильность должна быть неявной: пользователь не должен явно перемещать или копировать данные, чтобы сделать их стабильными.
Связи
В большинстве объектных систем связи неявно моделируются как свойства, значениями которых являются объекты. Например, если человек работает на некоторую компанию, то у каждого объекта-человека должно иметься свойство, которое можно назвать worksFor и значением которого является соответствующий объект-компания.23 Возникает проблема, если у объекта-компании имеется свойство, которое затрагивает множество служащих этой компании (например, employees – множество, включающее все объекты служащих данной компании). Эти два свойства являются несвязными, и поддержка их согласованности может вызывать значительную программистскую проблему.
В модели ODMG , подобно ER -модели, различаются два вида свойств – атрибуты и связи, хотя и несколько другим образом. Атрибутами называются свойства объекта, значение которых можно получить по OID объекта, но не наоборот. Значениями атрибутов могут быть и литералы, и объекты, но только тогда, когда не требуется обратная ссылка. Связи – это инверсные свойства. В этом случае значением свойства может быть только объект, поскольку литеральные значения не обладают свойствами. Поэтому возраст служащего обычно моделируется как атрибут, а компания, в которой работает служащий, – как связь.
При определении связи должна быть определена ее инверсия. В приведенном выше примере, если worksFor определяется как связь, должно быть явно указано, что инверсией является свойство employees объекта-компании, а при определении employees должна быть указана инверсия worksFor . После этого система баз данных должна поддерживать согласованность связанных данных, что позволяет сократить объем работы программистов приложений и повысить надежность их программ.24 Если в объекте-компании свойство employees не требуется, то свойство объекта-служащего employees может быть атрибутом.
Типы и классы
Имеются две основные категории объектно-ориентированных систем, в одной из которых поддерживают классы, а в другой – типы. К первой категории относятся системы, опирающиеся на языки Smalltalk и Lisp . К представителям второй категории относятся, например, C ++ и Simula .
В объектно-ориентированной системе в понятии типа обобщаются общие черты множества объектов с одинаковыми характеристиками. Это понятие соответствует понятию абстрактного типа данных. Тип делится на две части – интерфейс и реализация. Пользователям типа видна только интерфейсная часть, а реализация объекта видна только проектировщику типа. Интерфейс состоит из списка операций вместе с их сигнатурами (т.е. набором типов входных параметров и типом результата). Реализация типа состоит из части данных и части операций. Часть данных описывает внутреннюю структуру данных объекта. В зависимости от мощности системы часть данных может быть более или менее сложной. Часть операций состоит из процедур, которые реализуют операции интерфейсной части.
Если система типов достаточно тщательно разработана, то система может произвести проверку типов во время компиляции, иначе некоторые проверки могут быть отложены до времени выполнения. Таким образом, типы главным образом используются во время компиляции для проверки правильности программ. Вообще говоря, в основанных на типах системах тип имеет специальный статус и не может быть изменен во время выполнения.
Понятие класса отличается от понятия типа. Его спецификация совпадает со спецификацией типа, но является более динамическим понятием. Класс характеризуется двумя аспектами: фабрика объектов и склад объектов. Фабрика объектов может быть использована для создания новых объектов посредством выполнения операции new данного класса операции или клонирования некоторого объекта-прототипа, являющегося представителем данного класса. Склад объектов означает, что к классу присоединяется его расширение, т.е. набор объектов, которые являются экземплярами класса. Пользователь может манипулировать складом, применяя операции ко всем экземплярам класса.
Классы используются не для проверки правильности программы, а скорее для создания и манипулирования объектами. В большинстве систем, в которых используется механизм классов, классы обладают таким же статусом, как переменные и значения, ими можно манипулировать во время выполнения программы, т. е. изменять их и передавать как параметры. В большинстве случаев это делает невозможным проверку типов во время компиляции, но придает системе большую гибкость и однородность. Здесь речь идет о так называемых “полнотиповых” языках программирования (баз данных), в которых действительно создается иллюзия, что с типами можно оперировать во время выполнения программы. Насколько известно автору, при реализации, тем не менее, обычно пытаются ограничить операции над типами таким образом, чтобы можно было выполнить эти операции во время компиляции.
Конечно, между классами и типами имеется значительное сходство, оба термина использовались в каждом из значений, а в некоторых системах отличие между ними и вовсе едва заметно. Авторы Первого манифеста не чувствовали себя вправе отдать предпочтение одному из двух подходов и оставляли право выбора за проектировщиком системы. 5
Однако требовалось, чтобы система предоставляла некоторый механизм структурирования данных, будь это классы или типы. Таким образом, классическое понятие схемы базы данных заменяется на понятие множества классов или множества типов.
Авторы не видели необходимости в том, чтобы система автоматически поддерживала экстент типа (т. е. набор объектов данного типа в базе данных) или, если экстент типа поддерживается, чтобы система предоставляла пользователю доступ к нему. Рассмотрим, например, тип “прямоугольник”, который может использоваться в различных базах данных многими пользователями. Не имеет смысла говорить о множестве всех прямоугольников, поддерживаемых системой, или производить операции над ними. Мы думаем, что более оправдано отдать на откуп пользователю поддержку его множества прямоугольников и манипулирование ими.С другой стороны, в случае такого типа как “служащий” весьма удобно, чтобы система автоматически сопровождала экстент этого типа.
Управление вторичной памятью
Управление вторичной памятью является классической чертой систем управления базами данных. Эта возможность обычно поддерживается с помощью набора механизмов. Среди них управление индексами, кластеризация данных, буферизация данных, выбор пути доступа и оптимизация запросов.
Ни один из этих механизмов не является видимым для пользователя – это просто средства повышения производительности системы. Однако эти средства настолько важны с точки зрения эффективности, что при их отсутствии система не сможет выполнять некоторые задачи (просто потому, что их выполнение будет занимать слишком много времени). Особо важна невидимость таких средств. Прикладной программист не должен писать программы для сопровождения индексов, распределять память на диске или перемещать данные между диском и основной памятью. Должна обеспечиваться четкая независимость между логическим и физическим уровнями системы.
Versant
С 1988 г. компания Versant (http ://www .versant .com /) предлагает решения, основанные на хорошо масштабируемой объектно-ориентированной архитектуре и принадлежащем компании алгоритме кэширования. ООСУБД Versant является одной из немногих объектно-ориентированных систем, допускающих масштабирование уровня любого предприятия. Решения на базе Vers ant применяются в телекоммуникациях, обороне, на транспорте и т.д. Система работает как на основных UNIX-платформах, так и в среде Windows.
Архитектура Versant в большей степени ориентирована на логическое управления данными, т.е. объектами, а не на физическое представление данных в виде, например, страниц. Управление размещением объекта осуществляется системой способом, полностью прозрачным для пользователей. Для поддержки локальных хранилищ объектов используется кэширование.
Система обладает свойством отказоустойчивости. Для этого допускается синхронная репликация базы данных на двух серверах, которые могут находиться в одной локальной сети или разнесены в разные точки глобальной сети. В одной базе данных Versant может храниться около трехсот триллионов объектов, размер каждого из которых неограничен. Для архивации данных может использоваться третичная внешняя память с автоматическим оповещением оператора в случае потребности извлечения объектов из архива.
Поддерживаются кластеры совместно используемых объектов, причем встроенные объекты хранятся внутри своих объектов-предков, что способствует уменьшению уровня фрагментации памяти. Кластеризация применяется и при внешнем кэшировании. Кроме того, в системе Versant поддерживается возможность использования персональных баз данных, установленных на мобильных компьютерах. Они могут быть отсоединены от сервера центральной базы данных, использоваться автономно и зафиксировать свои изменения в центральной базе данных после восстановления соединения.
Управление транзакциями основывается, главным образом, на синхронизационных блокировках на уровне объектов, хотя возможны блокировки классов и версий объектов.
Имеется целый ряд разновидностей блокировок: короткие блокировки для коротких транзакций, стабильные блокировки для долгих транзакций и т.д. Допускается даже возможность расширения модели блокировки правилами, желательными для пользователей. Система избегает тупиковых синхронизационных ситуаций, не удовлетворяя запросы на блокировку, которые могут привести к тупику.
Фиксация распределенных транзакций основывается на двухфазном протоколе фиксации. Поддерживаются частичная фиксация кэшей, механизмы контрольных точек и точек сохранения. Обеспечивается и возможность образования вложенных транзакций. При реализации долгих транзакций используется механизм check -in /check -out с установкой стабильной блокировки на требуемые объекты, предотвращающей доступ к этим объектам со стороны других транзакций до завершения данной долгой транзакции.
Имеется возможность регистрации на сервере событий, которые интересуют приложения. При регистрации серверу сообщается вид события и операция, которую следует выполнять при возникновении события. К событиям, которые разрешается регистрировать, относятся обновление и удаление классов, создание, обновление и удаление объектов.
Для повышения надежности хранения баз данных поддерживаются два вида журналов – логический и физический. При необходимости восстановления базы данных по архивной копии все зафиксированные к моменту сбоя транзакции повторно воспроизводятся по логическому журналу.
Обеспечивается ссылочная целостность базы данных и прозрачность месторасположения объектов в распределенной среде. Объекты могут мигрировать по узлам сети, что способствует балансировке нагрузки, и оставаться полностью доступными для приложений. Допускается динамическая модификация классов, приводящая к автоматической модификации всех существующих в базе данных объектов этих классов. При этом система все время остается в рабочем состоянии, и приложения продолжают выполняться. Поддерживается развитый механизм версий. По известной версии объекта можно получить доступ к его предкам, потомкам и братьям.
Для представления связей между объектами базы данных используется единый стабильный указательный тип. В системе поддерживаются скрытые от пользователей преобразования указателей базы данных в обычные указатели C ++ и наоборот. Поэтому объекты создаются и ликвидируются с помощью стандартных конструкторов и деструкторов классов.
Для программирования можно использовать языки C ++ и Smalltalk , причем безо всяких расширений. Поддерживаются возможности, специфичные для работы с базами данных. Например, имеется средство автоматической генерации схемы базы данных прямо по файлам заголовков C ++. Это позволяет обойтись без использования специализированных препроцессоров или компиляторов. Специальные системные классы позволяют работать со всеми разновидностями типов коллекций, специфицированными в стандарте ODMG . Любой объект, созданный в среде C ++, доступен в среде Smalltalk и наоборот.
Запросы к базам данных Versant можно задавать с помощью специального системного класса, позволяющего обходить объекты коллекций. Поддерживается расширенный вариант SQL /89. Имеется драйвер ODBC . Обеспечивается доступ из среды Versant к внешним реляционным базам данных.
Версии
Большинство новых приложений (CAD /CAM и CASE ) включают проектную деятельность и требуют поддержки версий в том или ином виде. Поэтому во многих ООСБД поддерживаются версии. И в этом случае обеспечение механизма поддержки версий не является ключевым требованием к системе.
Входные данные и результаты запросов
Как утверждается в стандарте ODMG 3.0, “OQL -запрос является функцией, вырабатывающей объект, тип которого может быть выведен на основе операций, которые участвуют в выражении запроса”.
Вот несколько примеров простых OQL -запросов (мы будем использовать в этих примерах определенные в предыдущем подразделе классы DEPT и EMP в предположении, что DEPARTMENTS и EMPLOYEES являются именами экстентов этих классов).
Пример 2.1. Найти даты рождения служащих, зарплата которых превышает 20000 руб.
SELECT DISTINCT E.EMP_BDATE
FROM EMPLOYEES E
WHERE E.EMP_SAL > 20000.00
Легко видеть, что этот запрос по своему виду ничем не отличается от соответствующего запроса к таблице EMP , выраженного на языке SQL . В данном случае результатом запроса будет литеральное значение типа set < date > , т.е. литеральное значение-множество, элементами которого являются значения типа date.
Пример 2.2. Найти имена и даты рождения служащих, зарплата которых превышает 20000 руб.
SELECT DISTINCT STRUCT (name: E.EMP_NAME, bdate: E.EMP_BDATE)
FROM EMPLOYEES E
WHERE E.EMP_SAL > 20000.00
Запрос снова очень похож на соответствующий запрос на языке SQL, а результатом запроса является литеральное значение-множество, элементами которого являются значения типа struct { string <20> name ; date bdate }. Наверное, для конечного пользователя языка OQL строгий вывод типа результата запроса может показаться избыточным, но для программистов приложений это свойство является очень важным.
Если предположить, что в классе EMP определена операция age , значением которой является возраст соответствующего служащего, то результатом запроса
SELECT DISTINCT STRUCT (name: E.EMP_NAME, age: E.age)
FROM EMPLOYEES E
WHERE E.EMP_SAL > 20000.00
будет литеральное значение-множество, элементами которого являются значения типа struct { string <20> name ; interval age } (пример 2.2a ).
Пример 2.3. Получить номера менеджеров отделов и тех сотрудников их отделов, зарплата которых превышает 20000 руб.
SELECT DISTINCT STRUCT ( mng: D.DEPT_MNG,
DHS: ( SELECT E
FROM D.CONSISTS_OF AS E
WHERE E.EMP_SAL > 20000.00 ) )
FROM DEPARTMENTS D
Внешне этот запрос снова похож на SQL -запрос со вложенным подзапросом, но это только внешнее сходство. Во-первых, в разделе FROM “подзапроса” мы имеем дело с переходом по связи CONSISTS _ OF от экземпляра объектного типа DEPT ко множеству экземпляров объектного типа EMP . Во-вторых, результатом запроса является литеральное значение-множество, элементами которого являются значения-структуры с двумя литеральными значениями, первое из которых есть атомарное литеральное значение типа INTEGER , а второе – литеральное значение-множество с элементами-объектами типа EMP. Более точно, результат запроса имеет тип set < struct { integer mng ; bag < EMP > DHS } >. Конечно, в “классическом” SQL такого быть не может, хотя в следующем разделе мы обсудим возможности объектно-реляционных расширений этого языка.
В OQL предполагается, что хранимые в базе данных объекты могут иметь индивидуальные имена. 35
Пример 2.4. Если, например, в базе данных сохраняется объект типа DEPT с именем main _ department, то результатом запроса
main _ department
будет являться соответствующий объект. Результатом запроса
main_department.CONSISTS_OF
будет литеральное значение-множество, состоящее из объектов типа EMP , ассоциированных через связь CONSISTS _ OF с объектом main _ department
36.
Наконец, в контексте OQL имя каждого экстента можно трактовать как имя объекта-множества. Поэтому результатом запроса
EMPLOYEES
будет литеральное множество, состоящее из всех объектов, которые содержаться в указанном экстенте.
Восстановление
И в этом случае система должна обеспечивать услуги того же уровня, который предоставляют современные системы баз данных. Другими словами, в случае аппаратных или программных сбоев система должна восстанавливаться, т. е. возвращаться к некоторому согласованному состоянию данных. Аппаратные сбои включают как сбои в работе процессора, так и сбои дисков.
Введение в объектную модель ODMG
Модель ODMG является объектной моделью данных, включающей возможность описания как объектов, так и литеральных значений. На разработку модели повлиял тот факт, что она предназначена для поддержки работы с базами данных, так что особо важной является эффективность доступа к данным. Большинство других объектных моделей (см. например, матрицу объектных моделей Фрэнка Манолы [9]) ориентировано на языки программирования, расc читанных на работу со всеми данными в основной памяти. В этом случае допустимо представлять все данные как объекты. Но если требуется управлять большим объемом данных, расположенных во внешней памяти, то требуется некоторый компромисс между “чистотой” модели и требуемой эффективностью. Модель ODMG подстраивается под специфику систем баз данных следующим образом:
Для баз данных, схем и подсхем обеспечивается набор встроенных объектных типов.
Модель включает ряд встроенных структурных типов, позволяющих применять традиционные методы моделирования баз данных.
Модель одновременно включает понятия объектов и литералов20.
В модели связи между объектами отличаются от атрибутов объектов (аналогично тому, как это делается в ER -модели).
Обсудим немного более подробно два последних пункта.
Введение в Первый манифест
Выделялись три характерные черты современного (пятнадцать лет назад!) состояния дел (в области объектно-ориентированных систем баз данных): (а) отсутствие общепринятой модели данных, (б) отсутствие формального базиса и (с) активная экспериментаторская деятельность.
В конце 80-х ситуация с реализациями объектно-ориентированных систем управления базами данных (ООСУБД) была аналогична ситуации с РСУБД в середине семидесятых (хотя в случае объектно-ориентированных систем наработок было больше). В случае реляционных систем, хотя и имелись некоторые разногласия по некоторым конкретным вопросам, таким как форма языка запросов, или должны ли отношения быть множествами или мультимножествами, эти различия были в большинстве случаев несущественными 1, и существовала общепринятая основополагающая модель. Люди, главным образом, занимались разработкой технологии реализации. Создатели Первого манифеста одновременно решали проблему спецификации системы и предлагали технологию для поддержки ее реализации.
В отношении спецификации системы было принято решение придерживаться Дарвинистского подхода (эволюционного отбора): существовала надежда, что из множества построенных экспериментальных прототипов сама собой появится подходящая модель. Авторы также надеялись, что одновременно с ней появится жизнеспособная технология реализации этой модели.
При опоре на экспериментаторскую деятельность имеется риск принять в качестве образца некоторую систему не потому, что она является оптимальной, а поскольку она появляется первой среди тех систем, которые обеспечивают значительный набор функциональных возможностей, отвечающих требованиям рынка. Это, к несчастью, типично для компьютерной области: первый продукт становится де-факто стандартом и таковым остается. 2 Такая ситуация существует, по крайней мере, для языков и операционных систем ( Fortran , Lisp , Cobol и SQL представляют хорошие примеры). Однако целью авторов Первого манифеста являлась не стандартизация языков, а уточнение терминологии.
Чрезвычайно важно прийти к согласию об определении систем объектно-ориентированных баз данных. В качестве первого шага к этой цели в Первом манифесте предлагались характеристики, которым должны отвечать такие системы. Авторы выражали надежду, что их труд будет рассматриваться как пробный шар и что другие специалисты либо докажут несостоятельность, либо подтвердят основные положения. Материал не являлся обзором положения дел в технологии объектно-ориентированных систем баз данных (ООСБД) и не претендовал на оценку современного состояния технологии; в нем всего лишь предлагался набор определений.
Характеристики систем объектно-ориентированных баз данных были разделены на три категории: обязательные (те, которым система должна удовлетворять для того, чтобы иметь право называться объектно-ориентированной), необязательные (те, которые могут быть добавлены для улучшения системы, но не являются обязательными) и открытые (те места, где проектировщик может выбрать решение из набора одинаково приемлемых решений). Оставлялась некоторая возможность маневра в том, как лучше сформулировать каждую характеристику (это касается как обязательных, так и необязательных характеристик).
Вычислительная полнота
С точки зрения языка программирования свойство вычислительной полноты является очевидным: оно просто означает, что любую вычислимую функцию можно выразить с помощью языка манипулирования данными системы баз данных. С точки зрения базы данных это является новшеством, так как SQL , например, не является полным языком (напомним, что речь идет про SQL 15-летней давности).
Авторы Первого манифеста не призывали проектировщиков объектно-ориентированных систем баз данных к созданию новых языков программирования. Вычислительную полноту можно получить, разумным образом опираясь на существующие языки программирования. Вычислительная полнота – это не то же самое, что “ресурсная полнота”, т.е. возможность доступа ко всем ресурсам системы с использованием внутренних средств языка. Система, даже будучи вычислительно полной, может быть не способна к полной поддержке приложения. Тем не менее, такая система является более мощной, чем система баз данных, которая обеспечивает только хранение и извлечение данных и выполняет простые вычисления с атомарными значениями. Легко заметить, что здесь опять под “плохой” системой понимается SQL -ориентированная СУБД. И последнее утверждение является не вполне справедливым, поскольку уже в SQL /89 обеспечивалась возможность встраивания операторов SQL в вычислительно полные императивные языки, т.е. на основе SQL и некоторого традиционного языка программирования можно было написать законченное приложение.
Вызовы методов
В OQL допускается вызов метода объекта с указанием действительных параметров или без их указания (в зависимости от сигнатуры метода объекта, или класса) в любом месте запроса, если тип результата вызова метода соответствует типу ожидаемого результата запроса. Если у метода отсутствуют параметры, то нотация вызова метода в точности совпадает с нотацией выбора атрибута или перехода по связи. Если у метода имеются параметры, то их действительные значения задаются через запятую в круглых скобках. Этот гибкий синтаксис освобождает пользователя от необходимости знать, является ли свойство хранимым (атрибутом) или вычисляемым (методом).44 Однако, если в классе (или интерфейсе) содержатся одноименные атрибут и метод без параметров, то для разрешения конфликта имен в вызове метода должны содержаться круглые скобки.
В примере 2.2a мы уже показывали вариант запроса, содержащего вызов метода. В модели ODMG допускаются методы, вырабатывающие результат в виде сложных объектов или коллекций литеральных значений или объектов. Например, представим себе, что в классе EMP определена операция HIGHER _ PAID , которая для данного объекта-служащего производит множество объектов-служащих того же отдела с большим размером зарплаты. Тогда возможен следующий запрос.
Пример 2.13. Найти названия проектов, в которых участвуют сотрудники отдела 632, получающие зарплату с размером выше среднего.45
SELECT DISTINCT E.HIGHER_PAID.participate_in.PRO_NAME
FROM EMPLOYEES AS E
WHERE E.EMP_NO = 632
Здесь мы предполагаем, что между классами EMP и PRO имеется связь “многие-к-одному” participates _ in - participants _ of (один сотрудник может принимать участие не более чем в одном проекте, но в любом проекте может участвовать произвольное число сотрудников).
Приведенный краткий обзор основных особенностей
Приведенный краткий обзор основных особенностей наиболее популярных коммерческих ООСУБД показывает, прежде всего, очень большую техническую разнородность этих систем. В общем смысле все системы соответствуют базовой модели ODMG , но следует обратить внимание, что крайне редко в качестве языка запросов поддерживается OQL , и ни в одной системе не поддерживается ODL .
Ни одна из компаний, производящих ООСУБД, так и не смогла набрать критическую массу, достаточную для того, чтобы стать лидером, диктующим моду в данной области (как это произошло с IBM и Oracle в области SQL -ориентированных СУБД). Крупные компьютерные компании так и не решились приобрести какой-нибудь продукт ООСУБД, чтобы развивать его и продвигать на рынке. Примером является поглощение одной из наиболее известных в мире ООСУБД компании ObjectSystems не самой крупной компьютерной компанией Progress Software . Компания Progress пошла на этот шаг не потому, что ей понадобилось владеть ООСУБД ObjectStore , а только по той причине, что ранее на основе этой СУБД в компании ObjectSystems был создан продукт eXcelon , предназначенный для управления XML -данными.
Когда появился и стал широко распространяться язык Java , казалось, что поддержка этого языка станет сильным козырем ООСУБД. В 1997 г. одна из крупнейших софтверных компаний Computer Associates выпустила на рынок ООСУБД Jasmine , в которой активно поддерживался язык Java . Объявляя о выпуске этого продукта, президент компании заявил, что по его оценкам в течение пяти лет Jasmine войдет в тройку наиболее доходных продуктов Computer Associates . Пять лет прошло, появилось сообщество пользователей Jasmine , но совсем не такое большое, как рассчитывало руководство компании.