W tej lekcji zrealizujemy pierwszy projekt z użyciem hibernate rozbudowując z kolejnymi lekcjami wcześniejszy artykuł o zapis do bazy danych sparsowanych informacji z rynku nieruchomości serwisu olx.
Na początku musimy pamiętać o:
1. dodaniu do naszej aplikacji zależności Hibernate
2. pliku konfiguracyjny o domyślnej nazwie hibernate.cfg.xml
3. sterowniku bazy danych
4. Encje JPA
5. zdefiniowanie w naszej aplikacji metody zwracającej SessionFactory (umożliwia tworzenie sesji odpowiedzialnych za łączenie się z bazą danych)
Przejdźmy do zastosowania tego co omówiliśmy do tej pory z wykorzystaniem poprzedniego artykułu. Najpierw musimy dodać zależności Hibernate oraz sterownik baz danych. Poniżej przykład dla aplikacji zbudowanej z wykorzystaniem Maven. Robimy to po przez dodanie odpowiednich zależności do projektu w pliku pom.xml.
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.3.11.Final</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.34</version> </dependency>
Plik konfiguracyjny hibernate.cfg.xml
Nazwa pliku może być dowolna. Zalecamy jednak aby pozostać przy domyślnej nazwie, aby nie trzeba było jej nadpisywać w kodzie programu. Jego budowa jest następująca:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://...?serverTimezone=Europe/Warsaw</property> <property name="hibernate.connection.username">...</property> <property name="hibernate.connection.password">...</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</property> <property name="hibernate.hbm2ddl.auto">update</property> <mapping class="..."/> </session-factory> </hibernate-configuration>
W pierwszej kolejności DTD, definiuje jaki jest to rodzaj dokumentu. Następna jest sekcja , która po kolei definiuje:
nazwa sterownika bazy danych, analogiczna do bazy danych z której korzystamy. Lista innych sterowników poniżej:
MySQL com.Mysql.Jdbc.Driver HSQLDB Org.Hsqldb.JdbcDriver Sybase Com.Sybase.Jdbc3.Jdbc.SybDriver Apache Derby Org.Apache.Derby.Jdbc.EmbeddedDriver IBM DB2 Com.Ibm.Db2.Jcc.DB2Driver PostgreSQL Org.Postgresql.Driver SQL Server (Microsoft Driver) Com.Microsoft.Sqlserver.Jdbc.SQLServerDriver Informix Com.Informix.Jdbc.IfxDriver H2 Org.H2.Driver
Kolejno mamy:
<property name="hibernate.connection.url">jdbc:mysql://...?serverTimezone=Europe/Warsaw</property>
host i nazwa bazy danych;
<property name="hibernate.connection.username">...</property>
użytkownik bazy danych;
<property name="hibernate.connection.password">...</property>
hasło użytkownika bazy danych;
<property name="hibernate.show_sql">true</property>
pokazywanie w logach aplikacji informacji o zapytaniach
<property name="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</property>
dialekt bazy danych, również analogiczna do bazy danych z której korzystamy
<property name="hibernate.hbm2ddl.auto">update</property>
Jeśli nie chcesz ręcznie tworzyć struktury bazy danych możesz dodać linijkę dopowiadająca za automatyczne jest stworzenie. Artykuł na temat strategi w zarządzaniu bazami danych z udziałem hiberante w kolejnym artykule.
JPA – Encje
Są to klasy na bazie POJO (Plain Old Java Object – to nic innego jak zwykłe klasy zawierające jedynie pola, domyślny konstruktor (czyli taki, którego nie implementujemy, domyślnie jest tworzony przez kompilator) i akcesory (gety i sety do każdego z pól). Pojęcie to powstału podczas rozwoju Java Enterprise Edition, gdzie istniały już pojęcia takie jak JavaBean, EntityBean czy SessionBean.) Pola klasy są polami które odpowiadają polom w bazie danych, a metody get i set pozwalają nam pobierać i zmieniać dane w encji. Encje posiadają następujące właściwości:
@Entity
@Table(name="inna_nazwa_tabeli_aniżeli_domyślna_klasa_person");
public class Person {
...
@Entity nad daną klasą – inaczej reprezentacja obiektowa danej tabeli, którą chcemy zmapować. Aby obiekt stał się obiektem encyjnym potrzebujemy opatrzyć go tą właśnie adnotacją.
@Table – jak sama nazwa wskazuje, definiuje za jaka tabelę odpowiada klasa. Adnotacja ta posiada szereg atrybutów, dzięki którym możemy doprecyzować jak nasza tabela ma być odwzorowana w bazie danych:
name określa nazwę tabeli (nie pisząc tej encji hibernate automatycznie zmapuje nam nazwę tabeli z nazwy klasy)
catalog określa katalog w jakim znajduje się tabela
schema określa schemę w jakim znajduje się tabela
uniqueConstraints umożliwia definiowane kodu DDL
@Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; ...
@Id – podpowiada, które pole jest jednocześnie kluczem głównym w bazie danych. Klucz główny możemy oczywiście wpisywać ręcznie, ale istnieje też możliwość automatycznego generowania. Aby tego dokonać wystarczy umieścić adnotację @GeneratedValue.
@Column(name = "inna_nazwa_kolumny_aniżeli_domyślne_pole_nazwa", length = 100)
private String nazwa;
...
@Column – podobnie jak z tabelą, ta adnotacja mówi nam o kolumnie, do której przypisane jest dane pole. Adnotacja ta posiada szereg atrybutów, dzięki którym możemy doprecyzować jak nasza kolumna ma być odwzorowana w bazie danych:
name nazwa kolumny (nie pisząc tej encji hibernate automatycznie zmapuje nam nazwę kolumny z nazwy pól)
uniwue czy kolumna ma być unikalna
nullable czy wartość kolumny jest wymaga
insertable czy kolumna ma być brana pod uwagę podczas zapisu
updateable czy kolumna ma być brana pod uwagę podczas aktualizacji
uniqueConstraints umożliwia definiowane kodu DDL
length określa długość kolumny typu VARCHAR
table nazwa tabeli w jakiej znajduję się pole
precision dla kolumn o typie numerycznym, ustalamy ilość liczb po lewej stronie przecinka
scale dla kolumn o typie numerycznych, ustalamy ilość liczb po prawej stronie przecinka
– Posiadają co najmniej jeden bezparametrowy konstruktor;
– Getery i setery do pól;
– Dobrą praktyką jest dodanie interfejsu Serializable (wymagane przy stosowaniu kluczy złożonych);
Definiujemy klasy encji
Właściwości jakie posiada klasa encji zostały opisane powyżej, kod dla klasy Property wygląda następująco;
package com.example.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Property { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String title; private String size; private Double price; public Property() { } public Property(Long id, String title, String size, Double price) { this.id = id; this.title = title; this.size = size; this.price = price; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getSize() { return size; } public void setSize(String size) { this.size = size; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } @Override public String toString() { return "Property{" + "id=" + id + ", title='" + title + '\'' + ", size=" + size + ", price=" + price + '}'; } }
Powoływanie SessionFactory
Domyślna implementacja SessionFactory.
public class HibernateFactory { public SessionFactory getSessionFactory() { Configuration configuration = new Configuration().configure(); StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()); SessionFactory sessionFactory = configuration.buildSessionFactory(registryBuilder.build()); return sessionFactory; } }
W kolejnym artykule omówimy automatyczne budowanie struktury bazy danych a także zaimplementujemy przykład pozwalający na dodawanie, usuwanie, modyfikowanie obiektów.