Moduł 04
Transkrypt
Moduł 04
Metody dostępu do danych dr inż. Grzegorz Michalski Na podstawie materiałów dra inż. Juliusza Mikody Jak działa JDO Podstawowym zadaniem JDO jest umożliwienie aplikacjom Javy transparentnego umieszczenia w bazie danych instancji dowolnych klas zdefiniowanych przez programistę, a następnie ich odzyskanie przy możliwie niewielkiej liczbie ograniczeń. Aplikacja deleguje zadanie pobierania pól obiektów trwałych do implementacji JDO Implementacja JDO śledzi modyfikacje pól obiektów i zapisuje ich wartości w bazie danych w momencie zakończenia bieżącej transakcji. Klasa zdolna do trwałości Klasę zdolną do trwałości można utworzyć na trzy różne sposoby: Poprzez generowanie kodu źródłowego – klasa generowana jest od podstaw: generowanie kodu za pomocą narzędzia modelowania lub generowanie klas na podstawie istniejącego schematu bazy danych. Przez wstępne przetworzenie kodu źródłowego – na podstawie istniejącej klasy generowany jest nowy kod klasy przez odpowiednie narzędzia JDO. Klasa zdolna do trwałości Klasę zdolną do trwałości można utworzyć na trzy różne sposoby: Poprzez rozszerzenie kodu bajtowego – metoda ta działa bezpośrednio na kodzie bajtowym wygenerowanym wskutek kompilacji klasy javy. Rozwiązanie to sprawdza się nawet wtedy, gdy kod javy nie jest dostępny. Rozwiązanie takie jet zupełnie przeźroczyste dla programisty aplikacji, a rozszerzenie kodu bajtowego jest dodatkowym etapem wykonywanym po kompilacji klas. Podstawy JDO Specyfikacja JDO definiuje wiele interfejsów. Pięć głównych klas to: PersistenceManagerFactory – używana jest do pobierania instancji klasy PersistenceManager. PersistenceManager – zarządza połączeniem z bazą danych oraz buforem podręcznym obiektów trwałych, które zastały już zapisane w pamięci maszyny wirtualnej. Podstawy JDO Transaction – pozwala aplikacji na kontrolę granic pomiędzy kolejnymi transakcjami. Dla jednego obiektu PersistenceManager może istnieć jedynie jeden obiekt Transaction. Transakcje muszą być jawnie rozpoczęte, a następnie zatwierdzone lub odwołane Query – Posługująca się instancją PersistenceManager aplikacja może uzyskać wiele obiektów Query, które umożliwiają odnalezienie obiektu trwałego na podstawie wartości jego atrybutów. Extent – obiekt ten to reprezentacja wszystkich instancji danej klas. Definicja klasy JDO wymaga aby klasa zdolna do trwałości: Posiadała konstruktor bezargumentowy Konstruktor bezargumentowy służy do zainicjowania klasy przed pobraniem danych z bazy. Definicja klasy public class Osoba { private String nazwisko; private String imie; private long wiek; public Osoba() { this.nazwisko = this.imie = ""; this.wiek = 0; } public Osoba(String nazwisko, String imie, long wiek) { this.nazwisko = nazwisko; this.imie = imie; this.wiek = wiek; } public String getNazwisko() { return nazwisko; } public void setNazwisko(String nazwisko) { this.nazwisko = nazwisko; } Metadane JDO Dla każdej klasy zdolnej do trwałości JDO wymaga dodatkowych metadanych. Dane te muszą zostać umieszczone w pliku w postaci specyfikacji XML. Plik zawierający metadane ma rozszerzenie JDO. Każda klasa może posiadać własny plik metadanych: nazwa pliku tworzona jest na wzór nazwy klasy. Możliwe jest także istnienie pojedynczego pliku metadanych dla całego pakietu w którym znajduje się klasa. Metadane JDO <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 2.0//EN" "http://java.sun.com/dtd/jdo_2_0.dtd"> <jdo> <package name="test.jdo"> <class name="Osoba"> <field name="nazwisko" persistence-modifier="persistent"/> <field name="imie" persistence-modifier="persistent"/> <field name="wiek" persistence-modifier="persistent"/> </class> </package> </jdo> Połączenie z bazą danych PersistenceManagerFactory Transaction 0..1 0..* 0..* PersistenceManager Query 0..* Extent Tworzenie PersistenceManagerFactory Properties properties = new Properties(); properties.setProperty( "javax.jdo.option.ConnectionDriverName", "oracle.jdbc.driver.OracleDriver"); properties.setProperty( "javax.jdo.option.ConnectionURL", "jdbc:oracle:thin:@oracle2.icis.pcz.pl:1521:ICIS"); properties.setProperty( "javax.jdo.option.ConnectionUserName", "user"); properties.setProperty( "javax.jdo.option.ConnectionPassword","pass"); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(properties); Tworzenie i zapis obiektu PersistenceManager pm = pmf.getPersistenceManager(); Transaction tx=pm.currentTransaction(); try { tx.begin(); Osoba o = new Osoba("Igrekowski", "Robert", 20); pm.makePersistent(o); tx.commit(); } finally { if (tx.isActive()) tx.rollback(); } pm.close(); Odtwarzanie obiektów Wykonanie i zatwierdzenie transakcji powoduje zapis obiektu do bazy danych. Obiekt trwały „nie istnieje” w pamięci (jest w określonym stanie przez JDO). Odczytanie obiektu trwałego jest możliwe w kolejnej/tej samej transakcji. tx.begin(); System.out.println(o); tx.commit(); Odczyt obiektów z bazy danych Klasa Extent reprezentuje kolekcję wszystkich zapisanych obiektów danej klasy. Klasa może odczytać także elementy klas pochodnych. Pobranie instancji następuje z klasy PersistenceManager: getExtent(java.lang.Class persistence[, boolean subclasses]) Parametr subclasses określa, czy ekstencja zwrócona przez metodę zawierać będzie jedynie żądaną klasę, czy również jej klasy pochodne. Zestaw obiektów try { tx.begin(); Extent<Osoba> e = pm.getExtent( test.jdo.Osoba.class, true); for (Osoba osoba : e) { System.out.println(osoba); } tx.commit(); } finally { if (tx.isActive()) tx.rollback(); } Odczyt wybranych instancji Do wyszukania wybranych elementów zestawu instancji służy klasa Query. Do formułowania zapytań służy uproszczony język JDOQL składnia przypominająca instrukcję if, np: ==,!=, <, <=. Pobranie wartości następuje na podstawie wywołania metody na rzecz instancji klasy : Query newQuery(Class persistance[, String filter]) Query newQuery(Extent persistances, String filter) Filtrowanie danych try { tx.begin(); Query q = pm.newQuery(test.jdo.Osoba.class, "nazwisko.startsWith(\"Igrek\")"); Collection<Osoba> e = (Collection<Osoba>) q.execute(); for (Osoba osoba : e) { System.out.println(osoba); } tx.commit(); } finally { if (tx.isActive()) tx.rollback(); } Aktualizacja danych try { tx.begin(); Query q = pm.newQuery(test.jdo.Osoba.class, "imie.startsWith(\"Igrek\")"); Collection<Osoba> e = (Collection<Osoba>) q.execute(); Osoba osoba = e.iterator().next(); osoba.setNazwisko("Zetowski"); q.closeAll(); tx.commit(); } finally { if (tx.isActive()) tx.rollback(); } Usuwanie obiektów stałych try { tx.begin(); Query q = pm.newQuery(test.jdo.Osoba.class, "nazwisko.startsWith(\"Igrek\")"); Collection<Osoba> e = (Collection<Osoba>) q.execute(); Osoba osoba = e.iterator().next(); if (osoba != null) pm.deletePersistent(osoba); q.closeAll(); tx.commit(); System.out.println("end"); } finally { if (tx.isActive()) tx.rollback(); }