Hibernate Każda poważniejsza aplikacja wymaga przechowywania danych w jakiejś bazie danych. Można realizować to na wiele sposobów. Można obsługę bazy danych pisać samodzielnie, do zera, albo skorzystać z gotowych frameworków – bo po co wynajdywać koło od nowa? Jednym z takich frameworków jest Hibernate. Wstęp Hibernate jest frameworkiem, który pozwala realizować w prosty i szybki sposób obsługę przechowywania danych w bazie danych, niezależnie od systemu baz danych. Hibernate będzie więc warstwą pośredniczącą pomiędzy systemem baz danych, a aplikacją, będzie tak zwaną warstwą dostępu do danych (ang. persistance layer). Przede wszystkim dostarcza on translację, czy też mapowanie obiektów ze świata Javy, na relacyjne bazy danych. Strukturę mapowania definiujemy przy użyciu kodu XML, w odpowiednich plikach. Ważną zaletą projektu Hibernate jest fakt, iż pozwala on zwiększyć wydajność warstwy dostępu do danych dzięki minimalizacji liczby zapytań (poprzez buforowanie). Rysunek 1 przedstawia odpowiednie warstwy aplikacji – jak widzimy, Hibernate jest pośrednikiem między aplikacją, a bazą danych. Ilustracja 1: Warstwy aplikacji Hibernate jest projektem open source, a jego liderem i inicjatorem jest Gavin King. Projekt został podzielony na kilka podprojektów takich, jak: • Hibernate Core - centralna część wszystkich projektów – pozostałe są jej rozszerzeniami; • Hibernate Annotations – pozwala na stosowanie adnotacji (zamiast dokumentów XML) do mapowania obiektów; • Hibernate EntityManager – dzięki temu rozszerzeniu można stosować technikę mapowania w zgodzie ze standardem Java Persistence Manager; • Hibernate Shards – ułatwia sterowanie Hibernate Core w przypadku wielu baz danych; • Hibernate Validator – dzięki temu rozszerzeniu otrzymujemy możliwość walidacji, czy też ograniczeń, które nałożymy na żądane pola; • Hibernate Search – pełnotekstowe wyszukiwanie w oparciu o bibliotekę Lucene; • Hibernate Tools – zestaw narzędzi, które ułatwiają pracę z frameworkiem (wtyczka do Eclipse, zadania dla Anta); • NHibernate – Hibernate dla platformy .NET. Hibernate posiada także dużą społeczność, zatem nietrudno uzyskać jakieś wsparcie w przypadku problemów. Rozpoczynamy pracę Na potrzeby artykułu, założymy, że korzystamy ze środowiska programistycznego NetBeans (wersja 6.8). Do budowania aplikacji wykorzystujemy także Mavena. Klikając prawym przyciskiem myszki na sekcję Librarier w drzewie projektu, z menu kontekstowego wybieramy opcję Add Dependencies. Pojawia się okno, w którym można wyszukać zależności (rys. 2). Wpisujemy Hibernate i czekamy, aż Maven znajdzie w swoim repozytorium odpowiednie dane. Ilustracja 2: Dodajemy Hibernate do projektu Spowoduje to automatyczną edycję pliku pom.xml przez NetBeansa. Kolejnym krokiem będzie utworzenie pliku konfiguracyjnego.hibernate.cfg.xml. Również to można zrobić automatycznie z wykorzystaniem NetBeansa, wybierając opcję dodania nowego pliku do projektu. Plik należy umieścić w katalogu src/main/resources. Jego treść przedstawiono na listingu 1. Listing 1. Treść pliku hibernate.cfg.xml <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Database connection settings --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://db4free.net:3306/helloworld</proper ty> <property name="hibernate.connection.username">helloworld</property> <property name="hibernate.connection.password">helloworldpass</property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">1</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <!-- Enable Hibernate's automatic session context management --> <property name="current_session_context_class">thread</property> <!-- Disable the second-level cache --> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">false</property> <!-- Drop and re-create the database schema on startup --> <property name="hbm2ddl.auto">update</property> <mapping resource="com/helloworld/User.hbm.xml"/> </session-factory> </hibernate-configuration> Kluczowymi informacjami, które tutaj podajemy, to dane dostępu do bazy danych (znaczniki: <property name=”hibernate.connection.url”/>, <property name=”hibernate.connection.username”/>, <property name=”hibernate.connection.password”/>), informacje o typie bazy danych, oraz pliki z zdefiniowanym mapowaniem (znaczniki <mapping resource=”...”/>). Następnie tworzymy właśnie pliki z definicjami mapowanie, w naszym przypadku jest to User.hbm.xml. Jego zawartość przedstawiono na listingu 2. Tworzymy także odpowiadający mu pilk z definicją klasy opisującą mapowane obiekty (listing 3). Listing 2. Zawartość pliku User.hbm.xml <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping3.0.dtd"> <hibernate-mapping package="com.helloworld"> <class name="User" table="Users"> <id name="id" column="id"> <generator class="native"/> </id> <property name="login"/> <property name="password"/> <property name="email"/> </class> </hibernate-mapping> Listing 3. Zawartość pliku User.java //@Entity public class User implements Serializable { private Long id; private String login; private String password; private String email; public User() {} public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getLogin() { return login; } public void setLogin(String login) { this.login = login; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } } Pozostaje jeszcze utworzyć plik HibernateUtil.java, który pozwoli nam przeprowadzać operacje na bazie danych – listing 4. Również ten plik może zostać wygenerowany automatycznie przez NetBeansa poprzez wybranie opcji dodania nowego pliku do projektu. Listing 4. Plik HibernateUtil.java public class HibernateUtil { private static final SessionFactory sessionFactory = buildSessionFactory(); private static SessionFactory buildSessionFactory() { try { return new Configuration().configure("hibernate.cfg.xml").buildSessionFactory(); } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } private static SessionFactory getSessionFactory() { return sessionFactory; } public static void saveEntity(Object entity) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); Transaction transaction = session.beginTransaction(); session.save(entity); transaction.commit(); } public static List getEntities(Class criteria) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); Transaction transaction = session.beginTransaction(); List result = session.createCriteria(criteria).list(); transaction.commit(); return result; } } Przede wszystkim widzimy, że jest to singleton, który obiekt sessionFactory tworzy tylko raz. Parametryzujemy jego tworzenie poprzez podanie nazwy pliku konfiguracyjnego, który utworzyliśmy wcześniej. Poza tym, interesują nas właściwie dwie funkcje: saveEntity oraz getEntities. Pisząc kod HibarnateUtil.saveEntity(new User()), mamy już zapewniony zapis obiektu do bazy danych. Wcześniej należy oczywiście obiekt ten wypełnić odpowiednimi danymi. Podobnie rzecz ma się z pobieraniem obiektów z bazy danych przy pomocy funkcji getEntities. Tutaj otrzymamy na wyjściu listę. Jedynym kryterium, które podajemy, jest typ (klasa) obiektu, czyli w kontekście bazy danych – tabela. Zaznaczmy tutaj, że nie jest konieczne przygotowanie tabeli w bazie danych – Hibernate utworzy ją w razie potrzeby automatycznie. Podsumowanie Przygotowanie komunikacji między aplikacją a bazą danych jest niezwykle proste z użyciem frameworka Hibernate w roli warstwy pośredniczącej. Jego wsparcie dla licznych typów baz danych nie ogranicza nas tylko do jednego systemu, a duża społeczność dostarczy ogromne wsparcie. Zachęcam do pogłębienia wiedzy z zakresu tego projektu. Pamiętajmy, że decydując się na Hibernate nie jesteśmy zmuszeni do korzystania z Javy – można używać również platformy .NET.