Zpiratował Rafał Kaczyński
Jest to technologia pozwalająca mapować dane obiektowe na odpowiadające im struktury w bazach danych. Hibernate pozwala na dostęp do relacyjnej bazy danych z poziomu języka Java.
open source intuicyjne mapowanie tabel na klasy (za pomocą plików xml) mniejsza ilość kodu prostota możliwość korzystania z języka SQL HQL, Criteria narzędzia wspomagające (np. Hibernate tools)
Mozemy podzielic na grupy: Interfejsy do wykonywania operacji CRUD: Session, Transaction, Query Interfejs słuzacy do konfiguracji hibernate: Configuration Interfejsy słuzace do obsługi zdarzen hibernate (callback): Interceptor, Lifecycle, Validatable Interfejsy pozwalajace rozszerzyc funkcjonalnosc mapowania: UserType, CompositeUserType, IdentifierGenerator Hibernate korzysta takze z: JDBC Java Transaction API (JTA) Java naming and Directory Services (JNDI)
Session- sesja, pewna jednostka pracy Jeden z podstawowych interfejsów Koszt jego utworzenia i usuniecia jest niewielki szczególnie w przypadku aplikacji Webowych obiekt będzie tworzony i niszczony przy kazdym zadaniu Mozna myslec, ze jest kanał do bazy wraz z buforem obiektów Nazywany tez czasami zarzadca trwałosci (umozliwia m.in. na pobieranie i utrwalanie obiektów)
SessionFactory - fabryka sesji pozwala na otwarcie sesji. Najczęściej wywołuje ją się w bloku statycznym. W całej aplikacji wywołuje się ją raz za pomocą metody: Configuration.buildSessionFactory() Słuzy do tworzenia obiektów Session Jego utworzenie jest dosyc kosztowne i zalecane jest utworzenie jednej instancji dla całej aplikacji W przypadku dostepu do wielu baz, dla kazdej potrzebna bedzie osobna instancja Ten obiekt korzysta o plików mapujacych oraz tworzy odpowiednie struktury i zapytania SQL
Configuration- Configuration.configure() - pierwszy krok, odnalezienie pliku konfiguracyjnego (plik pobierany z zasobów) Słuzy do konfiguracji i uruchomienia hibernate Wczytuje plik konfiguracyjny Pierwszy obiekt zwiazany w hibernate Transaction - jeszcze mniejsza jednostka pracy (musi być zainicjalizowana sesja) Opcjonalny w uzyciu Pozwala samodzielnie zarzadzac transakcjami (Możemy ją odwołać lub zatwierdzić tx.commit(); tx.rollback() ;)
Query i Criteria Query pozwala zadawac zapytania w jezyku HQL lub SQL Criteria jest podobny, ale pozwala zadawac zapytania zorientowane obiektowo Interfejsy działaja zawsze w kontekscie jakiejs sesji
Interfejsy wywołan zwrotnych Interfejsy pozwalaja przechwytywac zdarzenia takie jak zapisanie, wczytanie, czy usuniecie obiektu Obiekty mogły implementowac interfejsy Lifecycle i Validatable, ale uznano to za zły kierunek i nie jest zalecane Zalecane jest uzywanie interfejsu Interceptor, którego uzycie nie wymaga implementacji czegokolwiek w samych obiektach biznesowych
Typy Hibernate ma własny zestaw typów wbudowanych, które dobrze koreluje z typami w jezyku Java Hibernate pozwala takze na tworzenie własnych typów poprzez interfejsy UserType i CompositeUserType
Interfejsy rozszerzen Hibernate daje mozliwosc implementacji interfejsów, dzieki którym mozemy zastapic domyslne zachowanie samodzielnie napisanym kodem. Co mozemy zaimplementowac? Generowanie wartosci klucza głównego (interfejs IdentifierGenerator) Dialekt SQL-a (klasa abstrakcyjna Dialect) Strategie buforowania (interfejsy cache i CacheProvider)
public class HibernateExample { private final static SessionFactory factory; static { // 1. Inicjalizacja Hibernate Configuration cfg = new Configuration().configure(); // 2. Utworzenie fabryki sesji Hibernate factory = cfg.buildSessionFactory(); } public static void main(String[] args) { HibernateExample m = new HibernateExample(); m.simpleFunction(); }
public void simpleFunction () { // 3. Otwarcie sesji Hibernate Session session = factory.openSession(); // 4. Rozpoczęcie transakcji Transaction tx = session.beginTransaction(); // 5. Utworzenie użytkownika User u = new User(); u.setImie("Jan"); u.setNazwisko("Nowak"); // 6. Zapisanie użytkownika w bazie danych session.save(u); // 7. Zatwierdzenie transakcji tx.commit(); // 8. Zamknięcie sesji Hibernate session.close(); }}
Do korzystania z Hibernate potrzebne są następujące składniki: biblioteka :) plik konfiguracyjny hibernate.cfg.xml pliki mapujące *.hbm.xml
hibernate-configuration> org.hsqldb.jdbcDriver jdbc:hsqldb:data/tutorial sa org.hibernate.dialect.HSQLDialect true
Pola w pliku konfiguracyjnym są dosyć intuicyjne. Najważniejsze to podanie: - sterownika, - adresu bazy - użytkownika i hasła - dialektu - klas mapujących (pliki *.hbm.xml) show_sql – pozwala wypisać komendy na konsolę Dodatkowe opcje: create - przy starcie aplikacji tworzy strukturę bazy danych
Te pliki zawierają właściwy opis mapowania, czyli tłumaczenia relacyjnego opisu danych na obiektowy i na odwrót. Zwykle plik *.hbm.xml odpowiada jednej klasie bądź tabeli. Dzieje się tak zwłaszcza wtedy gdy mamy prostą strukturę, gdzie tabele odpowiadają bezpośrednio klasom.
<class name="cat.model.Cat" table="CAT" > ten element określa klasę i tabelę której dotyczy mapowanie <property name="nick" type="java.lang.String" column="NICK" length="100 /> ten element opisuje pojedyncze pole i odpowiadającą mu kolumnę w tabeli
<many-to-one name="owner" class="cat.model.Owner" not-null="true" > Tu mamy przykład opisu relacji wiele-do-jeden - każdy kot ma swojego właściciela. Możliwe są oczywiście bardziej skomplikowane mapowania. W szczególności Hibernate wspiera różnego rodzaju dziedziczenie
Ładowanie obiektu z bazy. Jeżeli znamy identyfikator obiektu to możemy go załadować z bazy. Służą do tego dwie metody: Cat c = (Cat) session.load(Cat.class, id); c = (Cat) session.get(Cat.class, id); Jak widać, podajemy klasę i identyfikator i dostajemy obiekt, który musimy zrzutować na odpowiednią klasę. Semantyka metod różni się zachowaniem gdy nie ma elementu w bazie z tym identyfikatorem. Wtedy get zwraca null, zaś load - wyjątek Modyfikacja obiektu. Jeżeli załadowaliśmy obiekt z bazy (jest persystentny), to wszystkie modyfikacje są śledzone przez Hibernate i na końcu sesji (przy session.close()) zostaną zapisane. Jeżeli chcemy wymusić wcześniejsze zapisanie zmian to sesja ma metodę flush().
Zapisywanie obiektu: Jeżeli utworzyliśmy nowy obiekt to jest on w stanie transient. Aby zapisać go do bazy musimy wywołać. Cat c = new Cat(); c.setName("pus"); session.save(c); Metoda ta zwraca nowy identyfikator jaki został nadany obiektowi (gdy identyfikator jest generowany np. przez sekwencję).
Mapowanie polega na odwzorowaniu obiektu na dany rekord w bazie. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "
Znacznik class zawiera m. in. atrybuty name, który odpowiada klasie oraz table określający nazwę tabeli. Pomiędzy znacznikiem class znajduje się właściwe mapowanie pól klasy na odpowiadające im kolumny w bazie danych. Wymaganym znacznikiem jest id, który odpowiada za klucz główny, znaczniki property odpowiadają poszczególnym kolumną. Atrybuty znacznika property pozwalają na przykład określić rozmiar pola, możliwość przyjmowania wartości nullowych, typ złącznia itp.
HQL jest obiektowym odpowiednikiem języka SQL rozumiejącym takie aspekty jak dziedziczenie czy polimorfizm. HQL jest wrażliwy na rozmiar liter tylko jeśli chodzi o nazwy klas bądź pól, w pozostałych przypadkach SeLeCt == SELECT SELECT AVG(us.wiek), SUM(us.wiek), MAX(us.wiek), COUNT(us) FROM User AS us WHERE us.imie=Jan'
Wybieramy koty o imieniu Miau: select c from Cat c where c.name='Miau' order by c.id Wybieramy koty, których właściciel ma na imię Jan: select c from Cat c where c.owner.name = 'Jan' Wybieramy koty z właścicielami: select c, o from Cat c, Owner o where c.owner.id= o.id Tabele w zapytaniach zawsze muszą być aliasowane!
Mając obiekt Session możemy wykonać zapytanie w następujący sposób: Session session; Query q = session.createQuery("select c from Cat c where name = :id"); q.setString("id", "Miau"); //ustalamy parametry (możemy je także wpisać bezpośrednio) q.setFirst(0); //ustalamy od którego rekordu chcemy zapytania q.setMaxList(10); //ustalamy ile maksymalnie chcemy wyników List result = q.list() Lista zawiera teraz obiekty typu Cat.
Możemy także używać funkcji agregujących: select max(c.age) from Cat c I następnie np. q= session.createQuery("select max(c.age) from Cat ); Integer res = (Integer) q.uniqueResult() Ostatnia metoda daje wyjątek, gdy zapytanie zwraca więcej niż jeden rekord.
Hibernate pozwala na korzystanie również z czystego języka zapytań SQL. List users = sess.createSQLQuery( "SELECT {us.*} FROM user us WHERE us.wiek = 17).list();
Samodzielne generowanie plików mapujących jest oczywiście dość uciążliwe. Dostępnych jest kilka narzędzi, które potrafią wygenerować ze schematu bazy danych zarówno pliki mapujące jak i odpowiednie klasy.
Jest to narzędzie służące do szeroko pojętego "przekładania" języka relacyjnych baz danych na języki obiektowe. W szczególności ma wbudowany plug-in, pozwalający na generowanie plików mapujących. Można także dołączyć odpowiednie zadanie dla anta, pozwalające na generowanie kodu źródłowego (nazywa się hbm2java).
Jest to plug-in do eclipse, pozwalający na dodawanie plików mapujących, konfigurację i generowanie kodu klas, jak również generowanie schematu bazy na podstawie plików mapujących. Funkcjonalność jest jak widać bogatsza niż dla middlegena, jednak projekt jest rozwojowy i wiele rzeczy nie działa najlepiej.
Xdoclet zawiera zestaw anotacji (hibernate) i odpowienie zadanie (hibernatedoclet) pozwalające na generowanie plików mapujących na podstawie kodu klas.