Co to jest JDO i co nowego w JDO 2.0
JDO, czyli Java Data Objects to standard rozwijany w ramach JCP (akr. Java Community Process). Pierwotna wersja specyfikacji, JDO 1.0, powstała w wyniku prac nad JSR 12 (akr. Java Specification Request) i oparta była o standard ODMG 3.0 (akr. Object Data Management Group). Jej finalna wersja została zatwierdzona i opublikowana w kwietniu 2002. Aktualną wersję JDO, JDO 2.0, opracowano w ramach JSR 243 i zatwierdzono ostatecznie, po długotrwałych trudnościach natury politycznej, w maju 2006.
JDO jest standardem interfejsu programistycznego (ang. API) dla technologii trwałości danych. Główne idee, jakie stara się realizować to pełna niezależność od rodzaju źródła danych oraz przeźroczystość. Niezależność od rodzaju źródła danych oznacza, że aplikacja używająca JDO może być bez żadnych zmian w kodzie uruchamiana na relacyjnej, obiektowej oraz każdej innej bazie danych, a także na źródłach danych, których zwyczajowo nie nazywa się bazami danych. Przeźroczystość przejawia się w kilku aspektach, najważniejsze z nich to:
- Trwałość przez osiągalność (ang. persistence by reachability) – utrwalając obiekt, który ma referencje do innych obiektów obiekty osiągalne z obiektu utrwalanego explicite zostaną także utrwalone. Jeśli np. nasza klasa Osoba ma referencję nazwaną adresZamieszkania do obiektu typu Adres to utrwalając obiekt klasy Osoba, powiązany z nim obiekt klasy Adres zostanie także automatycznie utrwalony.
- Przeźroczysta nawigacja – pobierając pewien obiekt ze źródła danych nie pobieramy wszystkich obiektów, które są osiągalne z danego obiektu poprzez referencje. Wyobraźmy sobie obiekt klasy Sprzedawca, który ma referencje do wszystkich obsługiwanych przez siebie obiektów Klientów, którzy z kolei mają referencje do wszystkich swoich obiektów Zamówień, te mają dalsze referencje do obiektów klasy Towar. Byłoby to tysiące lub dowolnie dużo więcej obiektów do pobrania, podczas gdy my chcemy znać tylko imię i nazwisko danego sprzedawcy. Przeźroczysta nawigacja oznacza, że efektywnie pobierany jest tylko obiekt Sprzedawca, zaś dopiero odwołanie się do jego referencji powoduje rzeczywiste, ale zupełnie nie widoczne dla programisty, pobranie obiektu referowanego. Programujemy więc tak jakby wszystkie obiekty były pobrane od razu, ale rzeczywisty odczyt ze źródła danych następuje dopiero wtedy gdy jest to konieczne. Funkcjonalność ta dostępna jest jednak jedynie wtedy, gdy kod wykonuje się w kontekście zarządzanym przez managera JDO.
JDO jest jednak tylko standardem definiującym interfejs programistyczny. Aby mieć z niego jakikolwiek rzeczywisty pożytek niezbędna jest jeszcze implementacja. JDO realizuje ideę niezależności od rodzaju źródła danych tylko w tym sensie, że nie narzuca mechanizmów charakterystycznych dla np. relacyjnych baz danych, rzeczywista niezależność zależy od faktycznego istnienia odpowiedniej implementacji. Referencyjną implementacją dla JDO jest JPOX, http://www.jpox.org/. JPOX 1.0 implementuje JDO 1.0 dla relacyjnych baz danych, JPOX 1.1 to już JDO 2.0 ale również tylko dla relacyjnych baz danych. JDO 2.0 jest w pełni wstecz kompatybilne tak więc implementacja JDO 2.0 jest również implementacją JDO 1.0. JPOX 1.2 dodaje wsparcie dla obiektowej bazy danych DB4O, choć w chwili pisania tego artykułu nie ma jeszcze wersji stabilnej, najnowszą jest JPOX 1.2.0-beta-2. Spis dostępnych implementacji, choć nie wiem czy kompletny, można znaleźć na stronie http://db.apache.org/jdo/impls.html.
Jeśli mamy już w ręce pewien obiekt pobrany ze źródła danych, to kolejne obiekty pobieramy w sposób przeźroczysty, nie widoczny dla programisty, poprzez odwołanie się do referencji tego obiektu w zwykły, charakterystyczny dla Javy a nie dla JDO sposób. Jednak musimy jakoś pobrać ten pierwszy obiekt. Nie owijając w bawełnę. Praca z danymi wymaga istnienia dobrego mechanizmu wyszukiwania. JDO definiuje swój własny język zapytań, JDOQL. Zanim jednak popadniemy w zniechęcenie... JDOQL jest prosty, intuicyjny i... podobny do Javy. Tak! Do Javy, nie do SQL! Począwszy od JDO 2.0 JDOQL został rozszerzony w ten sposób, że można go używać także w bardziej SQL’owy sposób, ale nie trzeba, a udostępniono tą możliwość dlatego, że niektórzy tak wolą, oraz pewnie po to, żeby upodobnić JDO do JPA, ale to inna historia. Stworzenie prostego zapytania mogłoby wyglądać tak:
Query query = pManager.newQuery(Osoba.class, „wiek >= 50 && wiek < 60");
Jak duża jest różnica między JDO 1.0 a JDO 2.0? Ogromna! A właściwie to nie jest to różnica tylko różnice. Niektóre, istotne rozszerzenia, jakie wprowadza JDO 2.0 to:
- Standaryzacja mapowania obiektowo-relacyjnego – mimo że JDO nie jest w żaden sposób związane z relacyjnymi bazami danych, to w obliczu przytłaczającej dominacji RDBMS’ów jako źródeł danych zdecydowano się na standaryzację mapowania obiektowo-relacyjnego. Mapowanie to definiujemy w pliku XML, no i oczywiście nie musimy tego robić jeśli nie będziemy uruchamiać aplikacji na relacyjnej bazie danych.
- Rozszerzenie mechanizmu uruchamiania zapytań i języka zapytań JDOQL – liczne usprawnienia, w szczególności, umożliwienie wykonywania zapytań agregujących, np. zliczających liczbę obiektów lub wyliczających sumy, minima czy maksima. Dodanie mechanizmu projekcji, tak by możliwe było pobieranie tylko wybranych atrybutów obiektów, w tym możliwość projekcji do obiektów dowolnego typu. Dodanie mechanizmu stronicowania wyników zapytań.
- Mechanizm odłączania i przyłączania do kontekstu zarządzanego JDO – wydaje się to być niezbędne dla sprawnej implementacji nowoczesnych aplikacji wielowarstwowych i trudno mi jest wyobrazić sobie, że mogło tego pierwotnie nie być. Obiekt pozyskany ze źródła danych można teraz wyłączyć z kontekstu zarządzania JDO, zmodyfikować w innej warstwie i ponownie przyłączyć, co spowoduje zapisanie jego zmodyfikowanego stanu do bazy danych.
- Mechanizm definiowania zachłannego pobierania obiektów – mechanizm, który pozwala na zdefiniowanie, które obiekty powiązane referencjami z pobieranym obiektem zostaną pobrane w sposób zachłanny (ang. eager). Np. jeśli obiekt klasy Osoba posiada referencję do obiektu klasy Adres to możemy określić aby pobierając obiekt klasy Osoba pobrać od razu skojarzony z nim adres.
- Interfejsy zarządzania pamięcią podręczną drugiego poziomu – ze względów wydajnościowych wiele implementacji JDO 1.0 dostarczało pamięć podręczną (ang. cache) drugiego poziomu, tj. współdzieloną przez wszystkie obiekty managerów JDO. JDO 2.0 standaryzuje interfejs programistyczny do zarządzania tą pamięcią podręczną, choć specyfikacja dopuszcza brak rzeczywistej implementacji, tj. implementację w postaci zaślepki.