Bazy danych w systemach obiektowych

advertisement
Bazy danych w systemach
obiektowych
Problemy zarządzania danymi
•
Zarządzanie danymi sprowadza się do realizacji szeregu funkcji typowych
dla przetwarzania danych, w dużej mierze niezależnych od środowiska
implementacyjnego i przyjętej metodyki projektowania. Do najważniejszych
należą:
- trwałe i niezawodne przechowywanie dużych ilości informacji;
- zapewnienie efektywnego dostępu do tych informacji na żądanie, według
zadanych kryteriów wyszukiwania;
- zapewnienie możliwości modyfikowania przechowywania informacji;
- zagwarantowanie logicznej spójności (integralności) informacji, polegające na
niedopuszczaniu do realizacji takich operacji, które naruszają definicje danych
lub definicje wzajemnych powiązań logicznych pomiędzy poszczególnymi
fragmentami danych;
- ochrona danych, rozumiana jako zagwarantowanie tego, że na określonych
danych będą wykonywane jedynie dopuszczalne operacje i to przez określonych
z góry użytkowników (którymi mogą być programy aplikacyjne, ich poszczególne
składniki lub użytkownicy przy terminalach).
W konkretnym przypadku nie wszystkie z tych funkcji są jednakowo ważne.
Bazy danych w projekcie systemu
•
Konieczność uwzględnienia bazy danych w projekcie (i później w implementacji)
systemu może wynikać z kilku przyczyn takich jak:
- niektóre obiekty składające się na system muszą mieć cechę trwałości, czyli powinny
istnieć nie tylko w trakcie wykonywania programu, ale także po jego zakończeniu. Jest
istotne w takich sytuacjach, w których program uruchamiany jest wielokrotnie i korzysta z
wyników poprzedniego uruchomienia lub gdy wyniki jednego programu wykorzystywane są
przez inne programy.
- program może operować na dużych ilościach danych, niekoniecznie o charakterze
trwałym. W modelu obiektowym dane takie są zazwyczaj gromadzone w pojemnikach
danych w postaci obiektów, które przechowują i udostępniają te dane. Dla dużych składnic
danych znaczenia nabiera problem efektywnych metod organizowania danych w struktury w
pamięci zewnętrznej i dostępu do takich struktur według uniwersalnych kryteriów. Realizacja
takich metod (zwykle bardzo skomplikowanych) sposobami konwencjonalnymi jest trudna i w
praktyce nieopłacalna. Jednym z głównych zadań systemów baz danych jest zapewnienie
takich metod.
- jako narzędzie implementacyjne może zostać wybrane oprogramowanie do rozwoju
aplikacji, wchodzące w skład pakietu konkretnego systemu DBMS. Oprogramowanie
takie zawiera pewien język programowania, który wymusza na programiście stosowanie
określonych konstrukcji bazodanowych w programie aplikacyjnym. Rzutuje to na projekt
systemu, gdyż wówczas szereg decyzji projektowych wynika bezpośrednio z
zastosowanego języka. Jeśli jako narzędzie implementacyjne zostanie wybrany język
ogólnego przeznaczenia, projektant i programista zachowują większy wpływ na środki
zastosowane w implementacji programu, jednak kosztem konieczności stosowania wywołań
interfejsu programowania aplikacji oferowanego przez wykorzystywany system baz danych.
Systemy obiektowych baz danych - cechy
Najważniejszą cechą (poza jawnym uwzględnieniem obiektowego modelu
danych) jest jednolity język programowania, w którym obiekty trwałe i
obiekty programowe (nietrwałe) traktowane są identycznie. W takich
językach nie ma potrzeby dokonywania jawnego dostępu do bazy
danych (np. przez zanurzenie w programie zapytań formułowanych w
specjalnie do tego przeznaczonym języku dostępu do danych, innym niż
język programowania aplikacji); system zarządzania automatycznie
zrealizuje taki dostęp, jeśli tylko w programie nastąpi odwołanie do obiektu
przechowywanego w bazie danych. Cecha ta jest tak istotna, iż czasami
systemy obiektowych baz danych nazywa się „językami programowania
obiektowych baz danych”, a także „prawdziwymi systemami obiektowymi”.
Te prawdziwe systemy zarządzania obiektowymi bazami danych (ObjectOriented Database Management System – OODBMS) zaczęły powstawać
w drugiej połowie lat 80. Najważniejsze z nich to: Orion, Itasca, GemStone,
ObjectStore, Ontos, O2, Jasmine, Versant, Objectivity/DB, Statice, GBase.
Obiektowe bazy danych łączą w sobie obiektowy model danych z własnościami
charakterystycznymi dla tradycyjnych („klasycznych”) baz danych.
Podstawową jednostką manipulowania danymi w obiektowych bazach
danych jest obiekt, rozumiany jako kompletna, hermetyczna i
jednoznacznie identyfikowana struktura, obejmująca zarówno dane
(atrybuty), jak i zachowanie (metody).
Charakterystyczne cechy
Charakterystyczne cechy obiektowego modelu danych, odróżniające go od
modelu relacyjnego, a uwzględniane w obiektowych bazach danych, to:
- tożsamość obiektu (w modelu relacyjnym encje identyfikowalne są
jednoznacznym kluczem będącym pojedynczym atrybutem lub złożeniem kilku
atrybutów; w modelu obiektowym obiekty mają tożsamość niezależną od ich
wartości),
- hermetyzacja (zamknięcie danych i operujących na nich procedur we wnętrzu
obiektu, niedostępnym z zewnątrz; w modelu relacyjnym dane i procedury są
rozdzielone i ogólnie dostępne),
- agregacja (możliwość zagnieżdżania obiektów o dowolnej strukturze w innych
obiektach; w klasycznym modelu relacyjnym atrybuty są nierozkładalne i nie
mają wewnętrznej struktury),
- dziedziczenie (zdolność przejmowania właściwości, takich jak atrybuty i
zachowanie, od klas zdefiniowanych na wyższym poziomie abstrakcji; w modelu
relacyjnym nieobecne),
- rozszerzalność (swoboda definiowania nowych typów danych, stosownie do
potrzeb aplikacji; w modelu relacyjnym zestaw typów danych jest zdefiniowany z
góry i nie można go modyfikować),
- wersjowanie (możliwość utrzymywania wielu wersji tego samego obiektu; jest to
uogólnienie mechanizmów historycznych, czyli zależnych od czasu, baz danych).
Tradycyjne funkcje zarządzania
bazami danych (OODBMS)
• Trwałość obiektów i zarządzanie pamięcią
zewnętrzną,
• Interakcyjne języki zapytań (zapytań typy ad
hoc),
• Przetwarzanie transakcyjne,
• Realizacja współbieżnego dostępu do danych,
• Kontrola ograniczeń integralnościowych,
• Odtwarzanie po awariach,
• Ochrona danych i autoryzacja operacji,
• Narzędzia wspomagające tworzenie aplikacji.
Nowe funkcje obiektowych baz
danych
• Obsługa transakcji długotrwałych i zagnieżdżonych,
• Zupełność obliczeniowa języka manipulowania danymi,
w praktyce oznaczająca możliwość dokonywania takich
obliczeń, jak w proceduralnych językach programowania
(co jest znacznym rozszerzeniem w stosunku do
standardowego dla baz relacyjnych języka SQL),
• Zarządzanie wersjami obiektów i schematów baz
danych,
• Zarządzanie wielkimi obiektami o dowolnej strukturze,
takimi jak obiekty multimedialne,
• Szeroki zakres modyfikacji schematu bazy danych.
Przykład
• Prosta baza danych ma za zadanie
przechowywanie informacji o powiązaniach
rodzinnych. Dla każdego ojca interesuje nas:
jego identyfikator PESEL, imię i nazwisko oraz
zbiór jego dzieci. Dla każdego dziecka chcemy
przechowywać imię i datę urodzenia. Definicja
schematu takiej bazy danych podana zostanie w
trzech wersjach: wersji obiektowej (język OQL
systemu O2), w klasycznej wersji relacyjnej
(standardowy język SQL) oraz w rozszerzonej
wersji relacyjnej (rozszerzona wersja języka
SQL).
Przykład – model obiektowy
class Ojciec
type tuple
(pesel:
string,
imię:
string,
nazwisko:
string,
dzieci: set(Dziecko))
method podaj_opis_dzieci: set(string)
end
class Dziecko
type tuple
(imię:
string,
data_ur:
Date)
method wyświetl
end;
Komentarz
•
Schemat obiektowej bazy danych zawiera definicje dwóch klas: Ojciec i
Dziecko. Każdy obiekt klasy Ojciec ma wymagane atrybuty pesel, imię i
nazwisko oraz atrybut dzieci, którego wartością jest zbiór identyfikatorów
obiektów będących dziećmi danego ojca. Dla dziecka przechowujemy
jedynie atrybuty podające jego imię i datę urodzenia. Atrybut dzieci klasy
Ojciec w naturalny i logiczny sposób realizuje wiązanie pomiędzy ojcem a
jego wszystkimi dziećmi. Wiązanie to ma charakter jednokierunkowy:
przejście od ojca do zbioru jego dzieci jest bezpośrednie – wystarczy
odczytać wartość atrybutu dzieci. Znalezienie odpowiedniego obiektu klasy
Ojciec dla danego obiektu klasy Dziecko nie jest już tak proste: wymaga
przeglądania wartości atrybutu dzieci wszystkich obiektów klasy Ojciec w
celu odnalezienia poszukiwanego identyfikatora obiektu klasy Dziecko.
Jeśli w konkretnej aplikacji zachodzi częsta potrzeba wykonywania takiej
operacji, a liczba obiektów klasy Ojciec jest duża, sensowne może okazać
się dodanie do definicji klasy Dziecko dodatkowego atrybutu, który
implementuje wiązanie pomiędzy dzieckiem a jego ojcem w kierunku od
dziecka do ojca. W ten sposób, za pomocą dwóch atrybutów w dwóch
powiązanych ze sobą logicznie klasach zrealizowane zostanie wiązanie
dwukierunkowe.
Komentarz - cd
Zmieniona definicja klasy Dziecko, z dodanym atrybutem realizującym
takie dwukierunkowe wiązanie jest następująca:
class Dziecko
type tuple
(imię:
data_ur:
ojciec:
method wyświetl
end;
string,
Date
Ojciec)
Uwaga: W definicjach klas Ojciec i Dziecko, oprócz atrybutów
zawierają również nagłówki dwóch metod (bezparametrowych),
umożliwiające uzyskanie i wyświetlenie wybranych informacji o
obiektach tych klas. Takie połączenie wartości i operacji w jednym
elemencie aplikacji (w tym wypadku – w klasie), charakterystyczne
dla obiektowego modelu danych, jest bardzo naturalne i zarazem
wygodne dla użytkownika (klienta) klasy.
Przykład – model relacyjny
CREATE TABELE Ojcowie
(pesel
imię
nazwisko
CREATE TABELE Dzieci
(pesel
imię
data_ur
pes_ojca
CHAR(11),
CHAR(16),
CHAR(24);
CHAR(11),
CHAR(8),
DATE,
CHAR(11));
Komentarz – model relacyjny
•
Schemat relacyjnej bazy danych zawiera definicje dwóch relacji: Ojcowie i Dzieci.
Relacja Ojcowie ma jedynie atrybuty pesel, imię i nazwisko. Atrybut pesel jest
kluczem głównym tej relacji, gdyż jednoznacznie identyfikuje ojca (pojedynczą krotkę
relacji). W relacji Dzieci, z uwagi na trudności w rozróżnianiu krotek wyłącznie na
podstawie atrybutów oznaczających imię i datę urodzenia, również wprowadzono
atrybut pesel, który w sposób jednoznaczny identyfikuje dziecko (krotkę relacji) i jest
kluczem głównym tej relacji. Można założyć, że dopóki dziecku nie nadano urzędowo
numeru PESEL, system automatycznie przypisze mu pewien jednoznaczny numer z
zarezerwowanej do tego celu puli numerów (taka praktyka „numerowania” krotek
relacji jest bardzo pożyteczna w przypadku, gdy trudno określić klucz główny lub gdy
klucz główny składa się z wielu atrybutów). Związek między ojcami a dziećmi jest
reprezentowany w relacji Dzieci dodatkowym atrybutem pes_ojca. Atrybut ten pełni
rolę klucza obcego, co oznacza, że wartości tego atrybutu muszą być równe
wartościom klucza głównego innej relacji (w tym wypadku relacji Ojcowie). Wiązanie
między dzieckiem a jego ojcem ma w tym schemacie charakter jednokierunkowy,
przy czym jego kierunek nie może zostać w prosty sposób zmieniony (tak jak to miało
miejsce w obiektowej wersji schematu tej bazy danych). Istotnie, wymóg zachowania
pierwszej postaci normalnej nie pozwala na dodanie do schematu relacji Ojcowie
atrybutu wielowartościowego reprezentującego zbiór dzieci danego ojca (w tym
wypadku byłby to zbiór wartości klucza głównego relacji Dzieci). Dodanie wielu
atrybutów prostych, po jednym na każde dziecko, jest również niemożliwe, gdyż
liczba atrybutów w każdej krotce relacji musi być z góry ustalona i jednakowa.
Komentarz – model relacyjny
•
Z uwagi na jednokierunkowy charakter wiązania dziecko-ojciec, jedynie
operacja znalezienia ojca dla danego dziecka może być realizowana
bezpośrednio: wystarczy w tym celu odczytać wartość atrybutu pes_ojca
dla danej krotki relacji Dzieci. Symetryczna do niej operacja znalezienia
zbioru dzieci dla konkretnego ojca (czyli dla danej krotki relacji Ojcowie)
wymaga przejrzenia wszystkich krotek relacji Dzieci w poszukiwaniu tych
wartości atrybutu pes_ojca, które są równe wartości klucza głównego danej
krotki relacji Ojcowie. Jeśli taka operacja wykonywana jest często, a relacja
Dzieci zawiera dużą liczbę krotek, może okazać się konieczne
zastosowanie pomocniczych struktur zwanych indeksami, które pozwalają
na efektywną implementcję poszukiwania w danej relacji krotek o zadanej
wartości wybranego atrybutu. Standard języka SQL obejmuje instrukcje
pozwalające projektantom baz danych tworzyć indeksy, stosownie do
potrzeb danej aplikacji. W omawianym przykładzie, taki indeks posłużyłby
do realizacji (wielowartościowego) odwzorowania każdej z wartości klucza
głównego relacji Ojcowie w zbiór odpowiadających jej wartości klucza
głównego relacji Dzieci. Indeks taki posłużyłby do implementacji drugiego
kierunku związku pomiędzy ojcami a dziećmi.
Komentarz – model relacyjny
•
Standard języka SQL nie daje środków wspomagających zachowanie podstawowych
własności kluczy głównych i kluczy obcych. Od wartości klucza głównego relacji
wymaga się, by były jednoznaczne i niepuste. Od wartości klucza obcego w
konkretnej krotce wymaga się, by była albo pusta albo równa wartości klucza
głównego w pewnej krotce relacji z nią powiązanej. Aby wspomóc użytkownika w
zachowaniu tego typu ograniczeń integralnościowych, producenci wprowadzają różne
rozszerzenia do części języka SQL zwanej językiem definiowania danych (Data
Definition Language). Poniżej zamieszczono poprzedni schemat relacyjnej bazy
danych z uwzględnieniem możliwości, jakie daje język SQL z rozszerzeniami
wprowadzonymi przez firmę Informix. Atrybuty pełniące rolę kluczy głównych
opatrzono frazą PRIMARY KEY. Atrybut pełniący rolę klucza obcego opatrzono frazą
REFERENCES –daje to możliwość kontroli powiązań pomiędzy krotkami obu relacji.
CREATE TABELE Ojcowie
(pesel
CHAR(11) PRIMARY KEY,
imię
CHAR(16),
nazwisko
CHAR(24);
CREATE TABELE Dzieci
(pesel
CHAR(11) PRIMARY KEY,
imię
CHAR(8),
data_ur
DATE,
pes_ojca
CHAR(11) REFERENCES);
Komentarz – model relacyjny
• W schematach relacji Ojcowie i Dzieci nie ma
możliwości zawarcia definicji operacji, które mogą być
wykonywane na poszczególnych krotkach. Schemat
relacyjnej bazy danych zawiera jedynie opis danych, bez
opisu zachowania się (funkcji) elementów
przechowywanych w bazie. Jednak współczesne
systemy RDBMS dopuszczają możliwość
przechowywania w bazie danych nie tylko danych
statystycznych, ale także procedur (stored procedure),
choć wiązanie ich z danymi musi być nadal realizowane
jawnie przez program aplikacyjny.
Komentarz – rozszerzony model relacyjny
TYPE Dziecko = ROW
(imię
data_ur
CHAR(16),
DATE);
CREATE TABELE Ojcowie
(pesel
imię
nazwisko
dzieci
CHAR(11),
CHAR(16),
CHAR(24),
SET(Dziecko));
Komentarz – rozszerzony model relacyjny
•
•
Schemat relacyjnej bazy danych ograniczono tu do jednej relacji Ojcowie, przy czym w
porównaniu z odpowiadającą jej relacją z klasycznego modelu relacyjnego dodany został
atrybut wielowartościowy dzieci, reprezentujący zbiór dzieci danego ojca. Zastosowano tu
charakterystyczną dla rozszerzonych systemów relacyjnych możliwość zagnieżdżania
jednych krotek w innych (a więc odejścia od pierwszej postaci normalnej). W tym celu
zdefiniowano typ wierszowy Dziecko, definiujący strukturę krotek zawierających dane
dotyczące dzieci. Odpowiednie krotki z tymi danymi, będące konkretnymi wystąpieniami
typu Dziecko, zagnieżdżane są w stosownej krotce relacji Ojcowie. Rozwiązanie to jest
podobne do rozwiązania zastosowanego w modelu obiektowym; jednak występują tu
pewne zasadnicze różnice. W modelu obiektowym zdefiniowano oddzielną klasę Dziecko,
co powoduje, że obiekty tej klasy mają swoją tożsamość (atrybut dzieci klasy Ojciec
zawiera zbiór identyfikatorów obiektów będących dziećmi danego ojca, a nie zbiór
wartości tych obiektów). Natomiast w rozszerzonym modelu relacyjnym atrybut dzieci
relacji Ojcowie zawiera zbiór wartości atrybutów opisujących dzieci danego ojca. Związek
między dziećmi a ojcami został tu zrealizowany w postaci jawnego zagnieżdżenia wartości
jednej encji w innej encji, przy czym encja zagnieżdżona utraciła przy tym swoją
tożsamość (nie ma swojego klucza głównego, a więc nie może być odróżniona od
innych).
Rozwiązanie to można zmodyfikować na kilka sposobów. Jedną z możliwości jest dodanie
do definicji typu Dziecko atrybutu kluczowego pesel (analogicznie do modelu relacyjnego,
bez zmiany schematu relacji Ojcowie. Wówczas pozostaje implementacja związku przez
zagnieżdżenie, jednak encja zagnieżdżona nie traci swojej tożsamości (rozumianej jako
możliwość odróżnienia jej od innej encji tego samego typu). Drugą możliwością jest
zdefiniowanie oddzielnej relacji Dzieci, zawierającej dane opisujące dzieci, podobnie jak
to uczyniono w modelu relacyjnym. Taki schemat przejmuje z modelu obiektowego
możliwość stosowania atrybutów wielowartościowych (co np. umożliwia naturalną
implementację związków dwukierunkowych bez względu na krotność), a z modelu
relacyjnego realizację związków pomiędzy relacjami za pomocą kluczy obcych.
Komentarz – rozszerzony model relacyjny
CREATE TABELE Ojcowie
(pesel
CHAR(11),
imię
CHAR(16),
nazwisko
CHAR(24),
dzieci
SET(CHAR(11));
CREATE TABELE Dzieci
(pesel
CHAR(11),
imię
CHAR(8),
data_ur
DATE,
pes_ojca
CHAR(11));
W rozszerzonych systemach relacyjnych wprowadza się
pewne możliwości bezpośredniego wiązania danych z
operacjami.
Decyzje projektowe
• Problemy jakie występują, gdy model klas
projektowanego systemu chce się przełożyć na
projekt bazy danych dotyczą zwykle decyzji
projektowych lub czysto implementacyjnych. Podjąć
je należy w momencie przekładania modelu na projekt,
ukierunkowany na określone środowisko
implementacyjne. Charakter tych decyzji zależy w
dużej mierze od modelu danych przyjętego w systemie
baz danych w którym projektowana baza danych będzie
implementowana (decyzje odnośnie sposobu
implementacji związków między obiektami czy kwestie
zagnieżdżania danych).
Implementacja związków
•
•
•
Zależności pomiędzy klasami (zw. też związkami), występujące w modelu klas,
nie mają z góry określonej kierunkowości (z punktu widzenia logiki modelu są
dwukierunkowe). W projekcie bazy danych trzeba zdecydować się na ustalenie
kierunku związku, a ściślej – na sprecyzowanie kierunku połączenia (zw.
wiązaniem), istniejącego pomiędzy dwoma obiektami powiązanych ze sobą klas.
Z uwagi na możliwość definiowania w strukturze obiektu atrybutów
wielowartościowych, dowolny związek binarny można implementować w
postaci związku jednokierunkowego (w dowolnym kierunku) albo w postaci
związku dwukierunkowego. Niezależnie od krotności związku nie musimy do
jego implementacji używać żadnych oddzielnych struktur – wystarczy
dodanie odpowiedniego atrybutu do definicji klas. Tak uczyniono w
schemacie obiektowym (atrybut dzieci klasy Ojciec i atrybut ojciec
zmodyfikowanej klasy Dziecko) oraz w rozszerzonym schemacie relacyjnym w
jego drugiej wersji (atrybut dzieci relacji Ojcowie i atrybut pes_ojca relacji
Dzieci).
Implementacja związku w postaci dwukierunkowej nakłada dodatkowe
ograniczenia integralnościowe związane z aktualizacją wiązań. Ograniczenia te
polegają na tym, że:
- aktualizacja atrybutu reprezentującego wiązanie w jednym obiekcie musi pociągać za
sobą aktualizację odpowiedniego atrybutu w obiekcie z nim powiązanym,
- aktualizacja obu atrybutów musi być wykonana w ramach jednej transakcji (musi być
operacją atomową).
Uwaga: jeśli którykolwiek z powyższych warunków nie będzie zachowany, wiązanie
utraci charakter dwukierunkowości.
Implementacja związków - cd
• W modelu obiektowej bazy danych może być również
uzasadnione reprezentowanie związku przez specjalnie
w tym celu wprowadzoną klasę. Metodę tę należy
stosować wówczas, gdy stopień związku jest wyższy niż
dwa (tzn. liczba związanych ze sobą klas jest większa
niż dwa), a także wtedy, gdy z semantyki modelu wynika,
że ze związkiem skojarzone są konkretne atrybuty, które
nie są atrybutami klas pozostających w tym związku.
Występuje tu pełna zgodność z metodą postępowania
stosowaną podczas analizy obiektowej (związki
posiadające własne atrybuty stają się klasami).
Przykład
• Mamy klasę Mężczyzna i Kobieta, powiązane ze sobą związkiem
Małżeństwo. Pomiędzy dwoma obiektami z tych klas wiązanie
istnieje wtedy, gdy dwie osoby reprezentowane przez te obiekty
pozostają ze sobą w związku małżeńskim. Najlogiczniejszym
miejscem dla atrybutu oznaczającego datę zawarcie związku
małżeńskiego jest opis samego związku. Z każdym związkiem
wiążemy wówczas jedną wartość (datę). W momencie tworzenia
wiązania (czyli w chwili zawarcia związku małżeńskiego) tworzymy
nowy obiekt reprezentujący to wiązanie i nadajemy wartość jego
atrybutom (dacie). W zależności od tego, czy decydujemy się na
wiązanie jedno- czy dwukierunkowe, dodatkowo może zajść
potrzeba zapisania w odpowiednich obiektach klasy Mężczyzna i
klasy Kobieta wskazań na nowo utworzony obiekt klasy
Małżeństwo. Gdybyśmy atrybut oznaczający datę umieścili w obu
powiązanych ze sobą klasach, pojawiłyby się problemy wielu kopii
tej samej informacji oraz typowe problemy integralnościowe przy
aktualizacjach. Umieszczenie tego atrybutu w tylko jednej z tych
klas powodowałoby niejednakowe traktowanie tych klas, a tym
samym zachwianie logicznej spójności modelu.
Przykład – fragment schematu
•
•
Poniżej przedstawiono fragment schematu obiektowej bazy danych, w którym związek Małżeństwo
zaimplementowano jako klasę. W schemacie tym zastosowano wiązania jednokierunkowe pomiędzy
obiektami klasy Małżeństwo a odpowiadającymi im obiektami klasy Mężczyzna i klasy Kobieta.
Uwaga: Dla prostoty pominięto szereg atrybutów i metod, które mogłyby być istotne w danej bazie
danych, a także możliwość zastosowania uogólnienia, które mogłoby tu polegać na wydzieleniu
wspólnych atrybutów klas Mężczyzna i Kobieta (np. nazwisko i imię, adres) do wspólnej nadklasy.
class Mężczyzna
type tuple
end;
class Kobieta
type tuple
(nazwisko:string,
imię:
string,
…)
(nazwisko:string,
imię:
string,
…)
end;
class Małżeństwo
type tuple
end;
(data:
mąż:
żona:
Date,
Mężczyzna,
Kobieta)
Osadzanie obiektów
•
•
Osadzanie obiektów w innych obiektach może być uzasadnione ze względu
na efektywność. Dostęp do wartości obiektu osadzonego z poziomu
obiektu złożonego jest bezpośredni – polega jedynie na odczytaniu wartości
atrybutu (lub atrybutów). W wypadku przechowywania obiektów w bazach
danych należy się spodziewać, że wartości atrybutów jednego obiektu
położone są fizycznie blisko siebie, prawdopodobnie na jednej stronie
dyskowej lub – jeśli obiekt ma duży rozmiar – na niewielu sąsiadujących ze
sobą stronach. W związku z tym wartości te pobierane są do pamięci
operacyjnej bardzo efektywnie, zwykle w ramach jednej transmisji
dyskowej. Jeśli związany obiekt nie jest osadzony, a jedynie zagniżdżony
(tzn. w obiekcie złożonym istnieje jawne odwołanie do obiektu składowego,
poprzez jego identyfikator), wówczas dostęp do obiektu składowego
wymaga z reguły przynajmniej jeszcze jednego, dodatkowego dostępu do
dysku.
W projekcie schematu obiektowej bazy danych możliwy jest również proces
odwrotny do osadzania, polegający na wydzieleniu pewnej części wartości
obiektu i potraktowaniu jej jako samodzielnego, „pełnoprawnego” obiektu.
Może to być celowe, gdy zdarza się, że liczne obiekty tej samej klasy mają
tę samą wartość pewnych atrybutów.
Przykład – fragment bazy o osobach
• Baza danych zawiera m.in. Informacje adresowe.
Definicja klasy Osoba w takiej bazie może wyglądać
następująco:
class Osoba
type tuple
(nazwisko: string,
imię:
string,
adr_miasto: string,
adr_kod:
string,
adr_ulica:
string,
adr_nr_ul:
integer)
end;
Komentarz
•
Jeśli szereg osób mieszka pod tym samym adresem, wartości wszystkich atrybutów
o nazwach rozpoczynających się od adr_ będą się powtarzać. Rozszerzymy schemat
naszej bazy danych o klasę Adres, której wystąpieniami są adresy, pod którymi mogą
mieszkać osoby oraz zmodyfikujemy odpowiednio definicję klasy Osoba. W efekcie
uzyskamy następujący schemat:
class Osoba
type tuple
end;
class Adres
type tuple
end;
(nazwisko:
imię:
adres:
string,
string,
Adres)
(miasto:
kod:
ulica:
nr_ul:
string,
string,
string,
integer)
Obiekty z osadzonymi identycznymi adresami – graf kompozycji
id1
nazwisko imię
Nowak
id2
adres
nazwisko
Kłos
Jan
miasto kod ulica nr_ul
Olsztyn
10-900 Wąska
12
imię
adres
Jerzy
miasto kod ulica nr_ul
Olsztyn
10-900 Wąska 12
Różnice w zawartościach obu baz zobrazowano w grafach kompozycji dwóch
obiektów O1 i O2 klasy Osoba, o identyfikatorach odpowiednio O1 i O2 mieszkających
pod tym samym adresem. Na rysunku przedstawiono wariant w którym adres jest
wartością.
Obiekty z osadzonymi identycznymi adresami – graf kompozycji
Obiekty z identycznym adresem, reprezentowanym jako obiekt
id1
nazwisko imię
Nowak
id2
adres
Jan
adres
id3
imię nazwisko
Jerzy
Kłos
miasto kod ulica nr_ul
Olsztyn
10-900 Wąska
12
Zaprezentowane tu wydzielenie części wartości obiektu jako oddzielnego obiektu w
praktyce może mieć głębsze znaczenie niż tylko ukierunkowane implementacyjnie
zmniejszenie zajętości pamięci. Jeśli wydzielona struktura jest złożona, może okazać
się pożyteczne przypisanie do niej stosownych metod, np. służących do jej prezentacji
lub zmiany wartości. Takie postępowanie sprzyja polepszeniu modularności i
Trwałość obiektów
• Jednym z najważniejszych wymogów stawianych bazom danych
jest cecha trwałości (persistence), polegająca na tym, że dane
utworzone przez program mogą istnieć dłużej niż okres aktywności
tego programu. To jak długo mogą istnieć dane, zależy wyłącznie od
ich właściciela (zazwyczaj jest nim użytkownik, który je utworzył).
• Podejście obiektowe w zastosowaniu do baz danych wpływa w
istotny sposób na interpretację cechy trwałości elementów aplikacji,
w tym wypadku – trwałości obiektów. Jednym z istotnych postulatów
obiektowego modelu danych jest jednorodność, przejawiająca się w
różnych aspektach, także w aspekcie jednakowego traktowania
obiektów trwałych (przechowywanych w bazie danych) i obiektów
nietrwałych (programowych). Takie jednakowe traktowanie
przejawia się w tym, że operacje wykonywane na obiektach nie
zależą od cech trwałości obiektów. Jest to dodatkowy i bardzo
pożyteczny w praktyce aspekt niezależności programu od danych
(data independence).
Trwałość obiektów - wymagania
• Istotne wymagania odnośnie cechy trwałości obiektów
to:
- ortogonalność – trwałość obiektu nie zależy od klasy, do której
należy dany obiekt; innymi słowy, każdy obiekt, niezależnie od
jego klasy, może być uczyniony obiektem trwałym lub obiektem
nietrwałym;
- przezroczystość – obiekty trwałe i obiekty nietrwałe mogą być
traktowane w programie w ten sam sposób; innymi słowy, z
punktu widzenia programu aplikacyjnego, nie ma różnicy w
dostępie do danych rezydujących w pamięci operacyjnej i do
danych przechowywanych w pamięci dyskowej.
• Wszystkie „prawdziwe” systemy obiektowe spełniają
postulat przezroczystości (transparency). Spełnienie
postulatu ortogonalności zależy natomiast od
konkretnego systemu.
Przykład
•
Schemat osobowej bazy danych rozszerzono o definicję klasy kontenerowej o nazwie ZbiórOsób.
W tym schemacie zdefiniowano również obiekt nazwany TenZbiórOsób, będący wystąpieniem
klasy ZbiórOsób. Ponieważ obiekt TenZbiórOsób po utworzeniu go w klasie ZbiórOsób i
przypisaniu mu nazwy staje się obiektem trwałym, każdy obiekt klasy Osoba umieszczony w
zbiorze będącym atrybutem zbiór obiektu TenZbiórOsób staje się też obiektem trwałym. Również
każdy obiekt klasy Adres, do którego odwołuje się dowolny obiekt trwały klasy Osoba, jest
obiektem trwałym. Pozostałe obiekty klas Osoba i Adres są nietrwałe.
class ZbiórOsób
type tuple
(zbiór:
set(Osoba),
licznik:
integer,
method dodaj_osobę (osoba: Osoba),
…
end;
class Osoba
type tuple
(nazwisko:string,
imię:
string,
adres:
Adres)
end;
class Adres
type tuple
(miasto:
string,
kod:
string,
ulica:
string,
nr_ul:
integer)
end;
Name TenZbiórOsób: ZbiórOsób;
Baza danych - Armatorzy
•
System komputerowy (Armatorzy) ma zarządzać danymi o firmach
eksploatujących statki. Każda firma może mieć kilka siedzib (filii), przy czym
siedziby jednej z nich są uporządkowane według pewnego kryterium
ważności (nie jest one dla nas ważne). Każda siedziba ma swoją nazwę. W
jednej siedzibie może mieścić się wiele firm. Dla każdej firmy chcemy znać:
nazwę, rok założenia, liczbę zatrudnionych, a także wiedzieć, gdzie ma
swoje siedziby i jakie statki eksploatuje. Każdy statek eksploatowany przez
firmę ma nazwę i wyporność. Wśród statków wyróżniamy promy i żaglowce.
Każdy prom, oprócz atrybutów właściwych dla każdego statku, ma
określoną trasę kursowania. Dla każdego żaglowca, oprócz atrybutów
właściwych dla każdego statku, interesuje nas dodatkowo powierzchnia
żagli i typ żaglowca. Każdy statek eksploatowany jest przez jednego
armatora (firmę). Każdy został zwodowany w określonej stoczni. Dla każdej
stoczni interesuje nas: lokalizacja, określona przez miasto i państwo,
pewien parametr ekonomiczny (średni zysk ze sprzedaży jednego statku, w
procentach) oraz to jakie statki (spośród tych, które są eksploatowane przez
firmy) w niej zwodowano.
Diagram klas dla systemu Armatorzy
class Class Model
Firma
Statek
eksploatuje
-
Stocznia
zwodowany
nazwa:
rok-założenia:
zatrudnienie:
1.. -
nazwa:
wyporność:
-
miasto:
państwo:
zysk-jednostkowy:
ma siedzibę
{kolejność}
Żaglow iec
Prom
Siedziba
-
nazwa:
trasa:
-
powierzchnia_żagli:
typ:
Na diagramie zaznaczono jedynie te atrybuty, które zostały jawnie wymienione w
sformułowaniu problemu. W trakcie głębszej analizy pojawiłaby się konieczność
zawarcia w modelu innych atrybutów, a także operacji, które dla uproszczenia zostały
pominięte.
Schemat obiektowej bazy danych Armatorzy
class Class Model
Firma
Statek
nazwa:
rok-założenia:
statki:
zatrudnienie:
siedziby:
Stocznia
nazwa:
producent:
wyporność :
Prom
trasa:
miasto:
państwo:
zysk-jednostkowy:
Żaglow iec
powierzchnia_żagli:
typ:
Na schemat każdej obiektowej bazy danych składają się dwie hierarchie: hierarchia dziedziczenia,
reprezentująca związek nadklasa- podklasa oraz hierarchia kompozycji, reprezentująca związek
atrybut-dziedzina. W ogólności hierarchię dziedziczenia w obiektowej bazie danych można
przedstawić w postaci skierowanego grafu acyklicznego, natomiast hierarchię kompozycji w postaci
dowolnego grafu skierowanego. Węzłami w obu hierarchiach są te same klasy. Na diagramie
strzałki ciągłe oznaczają związek nadklasa-podklasa (są więc krawędziami w hierarchii
dziedziczenia), natomiast strzałki przerywane oznaczają związek atrybutu-dziedzina (są
krawędziami w hierarchii kompozycji). Znak * obok nazwy atrybutu oznacza, że jest to atrybut
wielowartościowy, czyli taki, którego wartością jest zbiór (jak atrybut statki klasy Firma) lub lista (jak
atrybut siedziby klasy Firma).
Przykład - Armatorzy
• Niżej zapisano ten schemat w języku definiowania
schematów systemu O2. zgodnie z konwencją przyjęto
w tym języku, dziedziny atrybutów pisane małą literą są
dziedzinami prymitywnymi (czyli takimi, których elementy
są wartościami atomowymi), natomiast dziedziny pisaną
dużą literą oznaczają klasy (elementami tych dziedzin są
identyfikatory obiektów odpowiednich klas). Klasy Prom i
Żaglowiec mają również atrybuty producent i wyporność,
choć nie występują one jawnie w opisach tych klas.
Atrybuty te są dziedziczone przez te klasy z klasy
Statek, co zapewnia fraza inherit występująca w
definicjach klas Prom i Żaglowiec. Aby zapewnić
trwałość obiektów z bazy Armatorzy, do schematu tej
bazy dodano nazwę ZbiórFirm, która będzie pełniła rolę
korzenia trwałości i w trakcie tworzenia bazy danych
zostanie przypisana do pustego zbioru obiektów klasa
Firma.
Przykład - Armatorzy
class Firma
type tuple
end;
class Statek
type tuple
end;
class Stocznia
type tuple
(nazwa:
rok_założenia:
statki:
zatrudnia:
siedziby:
string,
integer,
set(Statek),
integer,
list(string))
(nazwa:
producent:
wyporność:
string,
Stocznia,
integer)
(miasto:
string,
państwo:
string,
zysk_jednostkowy: integer)
end;
class Prom inherit Statek
type tuple
(trasa:
string)
end;
class Żaglowiec inherit Statek
type tuple
(powierzchnia_żagli:
typ:
string)
end;
name ZbiórFirm:
set(Firma);
integer,
Download