background image

Tworzenie warstwy 

trwałości danych w 

oparciu o Hibernate

Rafał Kasprzyk

background image

Rafał Kasprzyk

Ograniczenia na POJO

Wszystkie pola trwałe muszą być prywatne

Należy stworzyć accessory i mutatory dla 

pól trwałych

Musi istnieć bezargumentowy konstruktor 

może być domyślny

Jedno z pól powinno pełnić rolę 

identyfikatora encji (opcjonalnie)

Hibernate może sam zarządzać 

identyfikatorami obiektów, jednak nie jest to 

zalecane

Zalecany jest sztuczny identyfikator, typu nie-

prostego

Możliwość przypisania null

Zaleca się stosowanie wspólnego nazewnictwa 

np. id

Modyfikator final ogranicza możliwości 

strojenia wydajności 

background image

Rafał Kasprzyk

Zapytania do bazy danych

Zapytania w HQL (ang. Hibernate Query 

Language)

Język syntaktycznie i semantycznie podobny do SQL

SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, 

złączenia, podzapytania (o ile wspiera je DBMS)

Zorientowany obiektowo

Dziedziczenie, asocjacje, …

Zapytania poprzez obiekty Criteria

Zapytania budowane poprzez obiektowe API

Zapytania poprzez obiekty Example

QBE (ang. Query By Example)

Zapytanie budowane w oparciu o przykładową instancję

Filtry

Wykorzystywane do kolekcji i/lub tablic

Zapytania w zwykłym SQL

Możliwość wykorzystania specyficznych konstrukcji np. 

CONNECT

background image

Rafał Kasprzyk

Zapytania HQL

Domyślny mechanizm zapytań

HQL w swej strukturze jest bardzo 

podobny do SQL

Zapytania HQL definiowane są w dwóch 

miejscach:

W pliku definicji mapowania (preferowany 

sposób)

Możliwość modyfikacji zapytania bez rekompilacji 

kodu

Bezpośrednio w kodzie źródłowym

Obiekt reprezentujący zapytanie 

uzyskuje się z sesji Hibernate

Umożliwia on przypisanie parametrom 

zapytania wartości oraz pobranie wyniku w 

postaci listy bądź iteratora

background image

Rafał Kasprzyk

HQL (wykorzystanie listy)

Wynik zwracany jest do kolekcji w 

pamięci

Jedno odwołanie do bazy danych

List users = (List)session.createQuery(

"from User as user where user.surname = 'Kowalski'")
.list();

for (int i=0; i<users.size(); i++)

System.out.println(((User)users.get(i)).getName());

List users = (List)session.createQuery(

"select user.id, user.surname from User as user where
user.name = 'Jan'")
.list();

for (int i=0; i<users.size(); i++) {

Object [] tab = (Object []) users.get(i);
System.out.println(tab[0]+" "+tab[1]);

}

background image

Rafał Kasprzyk

HQL (wykorzystanie iteratora)

Wynik nie jest natychmiast ładowany 

do pamięci

Pobranie identyfikatorów

Wielokrotne wykonanie zapytania 

SELECT

Każda instancja wymaga odwołania się do 

bazy danych lub pamięci podręcznej jeżeli 

obiekty są już załadowane

Iterator users = session.createQuery(

"from User as user where user.surname = 'Kowalski'")
.iterate();

while (users.hasNext()) {

User user = (User) users.next();
System.out.println(user.getName());

}

background image

Rafał Kasprzyk

Przykłady zapytań w HQL

background image

Rafał Kasprzyk

HQL – operacje złączenia

Domyślnie w przypadku złączenia, 

Hibernate nie pobiera natychmiast 

związanych obiektów i kolekcji

Obiekty te są pobierane, gdy wystąpi pierwsze 

do nich odwołanie (tryb lazy)

Ewentualne ustawienia podane w pliku 

odwzorowań są ignorowane

Prowadzi to do problemów jeśli odwołanie do 

dowiązanego obiektu lub kolekcji nastąpi po 

zamknięciu sesji, w której wykonano zapytanie

Rozwiązaniem są klauzule (wynik zapisać do 

listy!!!)

INNER JOIN FETCH – dla pobrania pojedynczych 

obiektów

LEFT JOIN FETCH – dla pobrania kolekcji

from Employee as emp inner join fetch emp.dept

from Department as dept left join fetch dept.emps as emp

background image

Rafał Kasprzyk

HQL – dodatkowe mechanizmy

Zapytania sparametryzowane

Operator ?

List depts = (List)s.createQuery(

"from Department as dept 
where dept.loc = ?")

.setString(0, "Warszawa"); 

// numeracja od zera!

.list();

Parametry nazwane :name

List depts = (List)s.createQuery(

"from Department as dept 
where dept.loc = :city")

.setString("city", "Warszawa");
.list();

background image

Rafał Kasprzyk

HQL – dodatkowe mechanizmy

Zawężanie wyniku zapytania (ang. pagination)

Query q = s.createQuery(

"from Deptartment as dept 
where dept.loc = 'Opole'");

q.setFirstResult(0); 
q.setMaxResults(10);
List depts = q.list();

Kursory - przewijane wyniki zapytań

Wymaga otwartego połączenia z bazą i otwartego 

kursora

Sterownik JDBC musi wspierać kursory

Query q = s.createQuery(

"select ... from ...");

ScrollableResults kursor = q.scroll();

background image

Rafał Kasprzyk

HQL – zapytania nazwane

<query 

name="Employee.by.name.and.minimum.age">
<![CDATA[from Employee as emp 

     where emp.name = ? and emp.age > ?] ]>

</query> 

Query query = session.getNamedQuery(

"Employee.by.name.and.minimum.age");

query.setString(0, name);
query.setInt(1, minAge);
List emps = query.list();

background image

Rafał Kasprzyk

delete i update z poziomu HQL

Możliwość wykonania poleceń delete 

i update z poziomu HQL wprowadzona 

dopiero Hibernate w wersji 3

Przez długi okres twórcy Hibernate 

wzbraniali się przed implementacją takiej 

możliwości z powodu zawiłości jakie 

może to wprowadzić w kontekście cache 

pierwszego i drugiego poziomu

public  int clearEmployees() {
session session = factory.getSession();
return session.createQuery(„delete 

from Employee”).executeUpdate();

}

background image

Rafał Kasprzyk

Criteria API – zapytania 

dynamiczne 

Mechanizm pozwalający na dynamiczne 

konstruowanie zapytań

Sprawdza się wszędzie tam, gdzie trudno do 

końca stwierdzić, czego użytkownik końcowy 

aplikacji będzie chciał pozyskać z bazy 

danych

Wszelkie możliwe raporty, jakie będą generowali 

użytkownicy mogą nie być do końca znane

Można wówczas dostarczyć graficznego narzędzia 

do projektowania raportów wykorzystując Criteria 

API do realizacji właśnie dynamicznych zapytań

Obiekt reprezentujący zapytanie uzyskuje się 

z sesji Hibernate

Za pomocą metody add() wprowadza się do 

zapytania ograniczenia, a wynik może przyjąć 

postać listy bądź iteratora

Criteria API pozwala na prostą nawigację po 

zapytaniach i budowanie podzapytań

background image

Rafał Kasprzyk

Korzystanie z obiektu Criteria

List emps = session

.createCriteria(Employee.class)

.add(Restrictions.like("surname", "K%"))

.add(Restrictions.eq("sex", 'M'))

.add(Restrictions.between("salary", min, max)

.list();

List poorEmps = session

.createCriteria(Employee.class)

.add(Restrictions.like("name", "A%"))

.add(Restrictions.or

  (Restrictions.eq("salary",new Integer(0)),

   Restrictions.isNull("age"))) 
.list();

 

background image

Rafał Kasprzyk

Korzystanie z obiektu Criteria

List emps = session

.createCriteria(Employee.class)

.add( Restrictions.like("surname", "K%"))

.addOrder(Order.asc(surname))

.addOrder(Order.desc(name))

.setMaxResult(10);

.setFirstResult(50);

.list();

background image

Rafał Kasprzyk

Korzystanie z obiektu Criteria

List emps = session
.createCriteria(Employee.class) 
.add( Restrictions.in("name", new String[] { 

"Piotr","Anna","Katarzyna" } )) 

.add( Restrictions.disjunction() 
 .add( Restrictions.isNull("salary")) 
 .add( Restrictions.eq("salary", new Integer(0)))
 ) 
.list();

List emps = session.createCriteria(Employee.class)

.add( Restrictions.sql(

"lower({alias}.name) like lower(?)",
"K%", Hibernate.STRING))

.list();

background image

Rafał Kasprzyk

Korzystanie z obiektu Criteria

Object object = session
.createCriteria(Employee.class)
.setProjection(

Projections.projectionList()
.add(Projections.rowCount())
.add(Projections.min("salary"))
.add(Projections.max("salary"))
.add(Projections.avg("salary"))

)
.uniqueResult();

background image

Rafał Kasprzyk

Korzystanie z obiektu Criteria

List depts = session

.createCriteria(Department.class) 

.add(Restrictions.eq("loc", "Opole")) 
.createCriteria("emps")
.add(Restrictions.like("name", "K%"))
.list();

 

background image

Rafał Kasprzyk

Przykład wykorzystania 

Criteria API

Criteria criteria = session

.createCriteria(Employee.class);

criteria.add(Expression.like("name", name));
criteria.addOrder(Order.asc("name"));
criteria.setCacheable(true);

List emps = criteria.list();

background image

Rafał Kasprzyk

Wykorzystanie obiektów Example

Zapytanie budowane są w oparciu o 

przykładową instancję klasy trwałej

Employee emp = new Employee();
emp.setSex('F');

List emps = session
.createCriteria(Employee.class)
.add(Example.create(emp)).list();

 

List coworkers = session
.createCriteria(Employee.class) 
.add( Example.create(emp)) 
.createCriteria("unit") 

.add( Example.create( emp.getUnit() ) ) 

.list(); 

background image

Rafał Kasprzyk

Zapytania natywne SQL

W szczególnych przypadkach, gdy 

chodzi o optymalizację zapytań 

konieczne okazuje się wykorzystanie 

natywnych zapytań SQL

Programista doskonale znający 

wykorzystywany silnik bazy danych 

jest w stanie stworzyć zapytanie, 

które jest wydajniejsze niż jego 

odpowiednik wygenerowany z 

wykorzystaniem HQL lub Criteria API

Powstały kod staje się jednak trudno 

przenośny

background image

Rafał Kasprzyk

Przykłady zapytań natywnych 

SQL

List emps = session.createSQLQuery(

"select * from emps") 

.addEntity(Employee.class) 

.list(); 

List emps = session.createSQLQuery(

"select {emp.*} from emps emp")

.addEntity("emp", Employee.class) 

.list(); 

Query sqlQuery = session.createSQLQuery(

"select {emp.*} from emps {emp}",

"emp", Employee.class);

sqlQuery.setMaxResults(20);

List emps = sqlQuery.list();

background image

Rafał Kasprzyk

Przykład wykorzystania Filtrów

Collection Emps = session
.createFilter(dept.getEmps(), 
"where this.salary > 10 000" )
.list();

Collection tenEmps = session
.createFilter(dept.getEmps(), "")
.setFirstResult(0).setMaxResults(10)
.list(); 

background image

Rafał Kasprzyk

Podsumowanie

Ograniczenia na POJO

Zapytania HQL

Criteria API

Zapytania poprzez obiekt Example

Filtry

Zapytania natywne SQL


Document Outline