Trwałość obiektów i Java

Trwałość obiektu lub trwałość to termin, który często słyszysz w połączeniu z kwestią przechowywania obiektów w bazach danych. Oczekuje się, że wytrwałość będzie działać z uczciwością transakcyjną i jako taka podlega surowym warunkom. (Zobacz sekcję Zasoby tego artykułu, aby uzyskać więcej informacji na temat przetwarzania transakcji). Z kolei usługi językowe oferowane za pośrednictwem standardowych bibliotek i pakietów językowych są często wolne od ograniczeń transakcyjnych.

Jak zobaczymy w tym artykule, dowody sugerują, że prosta trwałość Java będzie prawdopodobnie wynikać z samego języka, podczas gdy dostawcy baz danych będą oferować zaawansowane funkcje bazy danych.

Żaden obiekt nie jest wyspą

W prawdziwym świecie rzadko można znaleźć obiekt, któremu brakuje relacji z innymi obiektami. Obiekty są składnikami modeli obiektów . Kwestia trwałości obiektu wykracza poza kwestię trwałości i dystrybucji modelu obiektowego, gdy zauważymy, że obiekty są ze sobą powiązane na mocy ich relacji między sobą.

Relacyjne podejście do przechowywania danych ma tendencję do agregowania danych według typu. Wiersze w tabeli reprezentują fizyczną agregację obiektów tego samego typu na dysku. Relacje między obiektami są następnie reprezentowane przez klucze, które są współużytkowane przez wiele tabel. Chociaż dzięki organizacji bazy danych relacyjne bazy danych czasami pozwalają na współlokowanie (lub zgrupowanie ) tabel, które mogą być używane razem, na tej samej partycji logicznej, takiej jak segment bazy danych, nie mają one mechanizmu przechowywania relacji między obiektami w bazie danych. Dlatego w celu skonstruowania modelu obiektowego relacje te są konstruowane z istniejących kluczy w czasie wykonywania w procesie określanym jako łączenie tabel . Jest to ta sama dobrze znana właściwość relacyjnych baz danych o nazwieniezależność danych . Prawie wszystkie warianty obiektowych baz danych oferują pewien mechanizm zwiększający wydajność systemu, który obejmuje złożone relacje obiektów w porównaniu z tradycyjnymi relacyjnymi bazami danych.

Aby zapytać lub nawigować?

Przechowując obiekty na dysku, stajemy przed wyborem kolokacji powiązanych obiektów w celu lepszego dostosowania dostępu nawigacyjnego lub przechowywania obiektów w kolekcjach przypominających tabele, które agregują obiekty według typu w celu ułatwienia dostępu opartego na predykatach (zapytania), lub obu . Kolokacja obiektów w trwałym magazynie to obszar, w którym relacyjne i obiektowe bazy danych znacznie się różnią. Wybór języka zapytań to kolejny obszar rozważań. Structured Query Language (SQL) i jego rozszerzenia zapewniły systemom relacyjnym mechanizm dostępu oparty na predykatach. Object Query Language (OQL) to obiektowy wariant języka SQL, ustandaryzowany przez ODMG, ale obsługa tego języka jest obecnie ograniczona. Metody polimorficzne oferują bezprecedensową elegancję w konstruowaniu semantycznego zapytania dla zbioru obiektów. Na przykład,wyobraź sobie polimorficzne zachowanie dlaacccountzadzwonił isInGoodStanding. Może zwrócić wartość logiczną prawda dla wszystkich kont o dobrej opinii lub fałsz w przeciwnym razie. Teraz wyobraź sobie elegancję odpytywania kolekcji kont, która inGoodStandingjest wdrażana w różny sposób w oparciu o reguły biznesowe, dla wszystkich kont o dobrej kondycji. Może to wyglądać następująco:

setOfGoodCustomers = setOfAccounts.query(account.inGoodStanding());

Chociaż kilka istniejących obiektowych baz danych jest w stanie przetwarzać taki styl zapytań w C ++ i Smalltalk, jest to dla nich trudne w przypadku większych (powiedzmy ponad 500 gigabajtów) kolekcji i bardziej złożonych wyrażeń zapytań. Kilka firm zajmujących się relacyjnymi bazami danych, takich jak Oracle i Informix, wkrótce zaoferuje inną składnię opartą na języku SQL, aby osiągnąć ten sam wynik.

Trwałość i typ

Miłośnik języka zorientowanego obiektowo powiedziałby, że trwałość i typ są ortogonalnymi właściwościami obiektu; to znaczy, trwałe i przejściowe obiekty tego samego typu mogą być identyczne, ponieważ jedna właściwość nie powinna wpływać na drugą. Alternatywny pogląd utrzymuje, że trwałość jest zachowaniem obsługiwanym tylko przez trwałe obiekty, a niektóre zachowania mogą mieć zastosowanie tylko do trwałych obiektów. To drugie podejście wymaga metod, które instruują trwałe obiekty, aby przechowywały i pobierały się z trwałego magazynu, podczas gdy pierwsze zapewnia aplikacji jednolity widok całego modelu obiektowego - często poprzez rozszerzenie systemu pamięci wirtualnej.

Kanonizacja i niezależność językowa

Obiekty tego samego typu w języku powinny być przechowywane w pamięci trwałej z tym samym układem, niezależnie od kolejności, w jakiej pojawiają się ich interfejsy. Procesy przekształcania układu obiektów do tego wspólnego formatu są wspólnie określane jako kanonizacja reprezentacji obiektów. W językach kompilowanych ze statycznym typowaniem (nie Java) obiekty napisane w tym samym języku, ale skompilowane w różnych systemach, powinny być identycznie reprezentowane w pamięci trwałej.

Rozszerzenie kanonizacji dotyczy reprezentacji obiektów niezależnych od języka. Jeśli obiekty mogą być reprezentowane w sposób niezależny od języka, różne reprezentacje tego samego obiektu będą mogły współużytkować ten sam trwały magazyn.

Jednym z mechanizmów realizacji tego zadania jest wprowadzenie dodatkowego poziomu pośrednictwa poprzez język definicji interfejsu (IDL). Interfejsy obiektowej bazy danych można tworzyć za pośrednictwem IDL i odpowiednich struktur danych. Wadą powiązań w stylu IDL jest dwojakie: po pierwsze, dodatkowy poziom pośrednictwa zawsze wymaga dodatkowego poziomu tłumaczenia, co wpływa na ogólną wydajność systemu; po drugie, ogranicza korzystanie z usług baz danych, które są unikalne dla określonych dostawców i mogą być cenne dla twórców aplikacji.

Podobnym mechanizmem jest obsługa usług obiektowych poprzez rozszerzenie SQL. Zwolennikami tego podejścia są dostawcy relacyjnych baz danych i mniejsi dostawcy obiektów / relacyjnych; Jednak dopiero okaże się, jak skuteczne będą te firmy w kształtowaniu struktury obiektowej pamięci masowej.

Pozostaje jednak pytanie: czy trwałość obiektu jest częścią zachowania obiektu, czy też jest to usługa zewnętrzna oferowana obiektom za pośrednictwem oddzielnych interfejsów? A co z kolekcjami obiektów i metodami ich odpytywania? Podejścia relacyjne, rozszerzone relacyjne i obiektowo / relacyjne zwykle opowiadają się za oddzieleniem języka, podczas gdy obiektowe bazy danych - i sam język Java - traktują trwałość jako nieodłączną część języka.

Natywna trwałość Java poprzez serializację

Serializacja obiektów to mechanizm specyficzny dla języka Java służący do przechowywania i pobierania obiektów Java i elementów podstawowych do strumieni. Warto zauważyć, że chociaż komercyjne biblioteki innych firm do serializacji obiektów C ++ były dostępne już od jakiegoś czasu, C ++ nigdy nie oferował natywnego mechanizmu serializacji obiektów. Oto jak używać serializacji Java:

// Zapisywanie „foo” do strumienia (na przykład pliku)

// Krok 1. Utwórz strumień wyjściowy

// to znaczy, utwórz zasobnik do odbioru bajtów

FileOutputStream out = nowy FileOutputStream ("fooFile");

// Krok 2. Utwórz ObjectOutputStream

// czyli utwórz wąż i włóż jego głowę do wiadra

ObjectOutputStream os = new ObjectOutputStream (out)

// Krok 3. Wpisz ciąg i obiekt do strumienia

// to znaczy pozwól strumieniowi wpłynąć do wiadra

os.writeObject ("foo");

os.writeObject (new Foo ());

// Krok 4. Opróżnij dane do miejsca docelowego

os.flush ();

W WriteobjectMETHOD serializowane bla i jego przechodni zamknięcia - to wszystkie obiekty, które mogą być użyte z foo w wykresie. W strumieniu istnieje tylko jedna kopia serializowanego obiektu. Inne odniesienia do obiektów są przechowywane jako uchwyty obiektów, aby zaoszczędzić miejsce i uniknąć odwołań cyklicznych. Zserializowany obiekt zaczyna się od klasy, po której następują pola każdej klasy w hierarchii dziedziczenia.

// Odczytywanie obiektu ze strumienia

// Krok 1. Utwórz strumień wejściowy

FileInputStream in = new FileInputStream ("fooFile");

// Krok 2. Utwórz strumień wejściowy obiektu

ObjectInputStream ins = new ObjectInputStream (in);

// Krok 3. Musisz wiedzieć, co czytasz

String fooString = (String) ins.readObject ();

Foo foo = (Foo) s.readObject ();

Serializacja i bezpieczeństwo obiektów

Domyślnie serializacja zapisuje i odczytuje niestatyczne i nietrwałe pola ze strumienia. Ta cecha może być używana jako mechanizm bezpieczeństwa przez deklarowanie pól, które mogą nie być serializowane jako prywatne przejściowe. Jeśli klasa może w ogóle nie być serializowana writeObjecti readObjectnależy zaimplementować metody do zgłaszania NoAccessException.

Trwałość dzięki integralności transakcyjnej: wprowadzenie JDBC

Modelowane na podstawie interfejsu SQL CLI (Client Level Interface) firmy X / Open i abstrakcji ODBC firmy Microsoft, łączność z bazą danych Java (JDBC) ma na celu zapewnienie mechanizmu łączności z bazą danych, który jest niezależny od bazowego systemu zarządzania bazami danych (DBMS). muszą obsługiwać przynajmniej podstawowy interfejs API ANSI SQL-2, który zapewnia niezależnym dostawcom narzędzi i aplikacjom wystarczającą elastyczność dostępu do bazy danych.

JDBC został zaprojektowany tak, aby był spójny z resztą systemu Java. Zachęcamy dostawców do pisania interfejsu API, który jest silniej wpisywany niż ODBC, co zapewnia lepsze statyczne sprawdzanie typów w czasie kompilacji.

Oto opis najważniejszych interfejsów JDBC:

  • java.sql.Driver.Manager obsługuje ładowanie sterowników i zapewnia obsługę nowych połączeń z bazą danych.

  • java.sql.Connection reprezentuje połączenie z określoną bazą danych.

  • java.sql.Statement działa jako kontener do wykonywania instrukcji SQL w danym połączeniu.

  • java.sql.ResultSet kontroluje dostęp do zestawu wyników.

Sterownik JDBC można zaimplementować na kilka sposobów. Najprościej byłoby zbudować sterownik jako pomost do ODBC. To podejście najlepiej sprawdza się w przypadku narzędzi i aplikacji, które nie wymagają wysokiej wydajności. Bardziej rozszerzalny projekt wprowadziłby dodatkowy poziom pośrednictwa do serwera DBMS, zapewniając sterownik sieciowy JDBC, który uzyskuje dostęp do serwera DBMS za pośrednictwem opublikowanego protokołu. Najbardziej wydajny sterownik miałby jednak bezpośredni dostęp do zastrzeżonego API DBMS.

Obiekty baz danych i trwałość Java

Szereg trwających projektów w branży oferuje trwałość Java na poziomie obiektów. Jednak w chwili pisania tego tekstu, PSE (Persistent Storage Engine) i PSE Pro firmy Object Design są jedynymi dostępnymi w pełni opartymi na Javie, zorientowanymi obiektowo pakietami bazy danych (przynajmniej o tym wiem). Sprawdź sekcję Zasoby, aby uzyskać więcej informacji na temat PSE i PSE Pro.

Rozwój języka Java doprowadził do odejścia od tradycyjnego paradygmatu programistycznego dla dostawców oprogramowania, w szczególności w odniesieniu do harmonogramu procesu tworzenia. Na przykład PSE i PSE Pro są opracowywane w heterogenicznym środowisku. A ponieważ nie ma etapu łączącego w procesie rozwoju, programiści byli w stanie tworzyć różne komponenty funkcjonalne niezależne od siebie, co skutkuje lepszym, bardziej niezawodnym kodem obiektowym.

PSE Pro ma możliwość odzyskania uszkodzonej bazy danych po przerwanej transakcji spowodowanej awarią systemu. Klasy odpowiedzialne za tę dodatkową funkcjonalność nie są obecne w wersji PSE. Nie ma innych różnic między tymi dwoma produktami. Produkty te to tzw. „Dribbleware” - wersje oprogramowania, które zwiększają ich funkcjonalność poprzez podłączanie nowych komponentów. W nie tak odległej przyszłości koncepcja zakupu dużego, monolitycznego oprogramowania odejdzie do przeszłości. Nowe środowisko biznesowe w cyberprzestrzeni, wraz z przetwarzaniem w języku Java, umożliwia użytkownikom zakup tylko tych części modelu obiektowego (graf obiektowy), których potrzebują, co skutkuje bardziej zwartymi produktami końcowymi.

PSE działa poprzez przetwarzanie końcowe i dodawanie adnotacji do plików klas po ich utworzeniu przez programistę. Z punktu widzenia PSE, klasy w grafie obiektów są trwałe lub świadome. Klasy z obsługą trwałych mogą utrzymywać się same, podczas gdy klasy z obsługą trwałych mogą działać na obiektach trwałych. To rozróżnienie jest konieczne, ponieważ wytrwałość może nie być pożądanym zachowaniem dla niektórych klas. Postprocesor plików klas dokonuje następujących modyfikacji klas: