I T 3 5 0 - B A Z E P O D ATA K A
Objektno Relaciono Mapiranje (ORM) Lekcija 14
IT350 - BAZE PODATAKA Lekcija 14
OBJEKTNO RELACIONO MAPIRANJE (ORM) Objektno Relaciono Mapiranje (ORM) Poglavlje 1: Objektno Relaciono Mapiranje (ORM) Poglavlje 2: Java ORM (Hibernete) Poglavlje 3: Hibernate Query Language (HQL) Poglavlje 4: Vežba: Pisanje Java koda uz pomoć Hibernate-a Poglavlje 5: Domaći zadatak 14 Zaključak
Copyright © 2017 – UNIVERZITET METROPOLITAN, Beograd. Sva prava zadržana. Bez prethodne pismene dozvole od strane Univerziteta METROPOLITAN zabranjena je reprodukcija, transfer, distribucija ili memorisanje nekog dela ili čitavih sadržaja ovog dokumenta., kopiranjem, snimanjem, elektronskim putem, skeniranjem ili na bilo koji drugi način. Copyright © 2017 BELGRADE METROPOLITAN UNIVERSITY. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, scanning or otherwise, without the prior written permission of Belgrade Metropolitan University.
www.metropolitan.ac.rs
Uvod UVOD Šta ćemo naučiti u ovoj lekciji? U ovom predavanju se govori o Objektno relacionom mapiranju (ORM) koje se koristi za konverziju podataka između relacioninih baza podataka i objektno orijentisanih programskih jezika. Postoji puno framework-ova za ORM u Javi među kojima su najpoznatiji Castor, TopLink I Hibernate. U okviru predavanj se koristi Hibernate. U predavanju su objašnjene klase Hibernatei definisana njihova namena. Korišćenje Hiberneta-a je objašnjeno na primeru MySQL baze Pre korišćenja, treba podesiti svojstva hibernete-a (hibernate.properties) keo što su dijalekt, URL za konekciju na baz, username i password. Da bi smo specificirali hibernate podešavanja iz primera u daljem tekstu će se koristiti hibernate.cfg.xml. Kako bismo hibernate-u objasnili kako da izvrši mapiranje klasa koriste se hibernate anotacije. Hibernate Query Language (HQL) je objektno orijentisan jezik koji za razliku od SQL koji izvršava operacije nad tabelama i kolonama relacione baze, radi sa perzistentnim objektima i njihovim property-ima
3
Poglavlje 1 Objektno Relaciono Mapiranje (ORM) ŠTA JE PERZISTENCIJA PODATAKA? Skoro sve aplikacije zahtevaju perzistentne (trajno sačuvane) podatke Skoro sve aplikacije zahtevaju trajno čuvanje nekih podataka. Perzistetnost (trajnost, stalnost) je jedan od osnovnih koncepata u razvoju aplikacija. Ukoliko informacioni sistem nije sačuvao podatke unete od strane korisnika kada se klijentska mašina isključi, onda je takav sistem od male praktične vrednosti. Ukoliko govorimo o čuvanju (trajnom) podataka u Javi, najčešće se misli na slakdišenje podataka u relacionu bazu podataka pomoću SQL-a. Naravno, ovo nije začuđujuće, jer se developeri svakodnevno susreću i rade sa bazama podataka (relacionim, NoSQL, ...). Ipak, relacione baze podataka su se, ne slučajno, ukorenile u razvoj aplikacija jer su neverovatno felsibilan i robustan pristup upravljanju podacima. Pristup upravljanju podacima i njhovom čuvanju su ključne odluke prilikom planiranja svakog projekta. Imajući u vidu da ovakvi problemi nisu novost u Javi ili nekoj drugoj aplikaciji, očekuje se da ste sposobni da napravite jednostvan izbor imeđu sličnih i proverenih rešenja. Nažalost, ovo možda nije još slučaj kada je u pitanju tehnologija sloja prezistencije, gde je moguće pronaći dosta različitih rešenja za isti problem.
4
Poglavlje 1 Objektno Relaciono Mapiranje (ORM)
Slika 1.1 za trajno čuvanje podataka (eng. Persistence layer) koji se nalazi između poslovnog sloja (aplikacije) i relacione baze podataka
OBJEKTNO-RELACIONO MAPIRANJE Automatizovano (i transparentnop) preslikavanja perzistentnih (trajnih) podataka iz objekata Java (ali i drugih) aplikacija u tabele relacionih baza podataka. Ukratko, objektno-relaciono mapiranje (ORM ) je automatizovan (i transparentan) proces preslikavanja perzistentnih (trajnih) podataka iz objekata Java (ali i drugih)aplikacija u tabele relacionih baza podataka. Ovaj procees koristi meta podatke kojima se opisuje mapiranje (preslikavanje) između objekata i baza podataka. Objektno-relacino mapiranje, u suštini, radi tako što transformiše (reverzibilno) podatke iz jedne reprezentacije u drugu. Ovakav pristup, nažalost, podrazumeva i određeno umanjenje perfomansi aplikacije. Međutim, ako se ORM implemtira kao middleware (srednji sloj), postoje mnoge mogućnosti za optimizaciju koje ne postoje ako bi se sloj perzistencije ručno kodirao. Dalji troškovi za vreme razvoja se odnose na upravljane meta podacima koji regulišu transformaciju podataka. Ali, i dalje, ti troškovi su manji od ekvivalentnih troškova koje bi imali ako bi radili i održavali ručno kodirani sloj perzistencije.
5
Poglavlje 1 Objektno Relaciono Mapiranje (ORM)
U slučaju kada se izradu aplikacije koristi Java, Objektno-relaciono mapiranje se može efikasno vršiti korišćenjem Hibernate ORM - o kome će uglavnom biti reči u ovom predavanju). Da bi koristili Hibernate potrebno je i odlično poznavanje relacionih modela, sistema za upravljenje bazama podataka ( MySQL, PostgreSQL, SQLIte, ... sa kojim povezujete vašu aplikaciju) i naravno samog SQL-a. Tačnije, morate upotrebiti vaše znanje SQL-a kako bi naštelovali perfomanse vaše aplikacije. Npr., Hibernate će automatizovati mnoge zadatke koje bi morali da iznova kodirate, ali vaše znanje o tehnologijmaa za čuvanju podataka mora biti šire, od samog Hibernate framework-a, kako bi iskoristili svu moć savremenih relacionih baza podataka. Uvek imajte na umu da je osnovni cilj snažano i efikasano upravljanje čuvanjem podataka.
Slika 1.2 Objektno relaciono mapiranje
ZAŠTO ORM? Zato što između objekata koje koristimo kao modele i same relacionalne baze postoje razlike Kada radimo sa Objektno-orijentisanim sistemima postoje razlike između objekata koje koristimo kao modele i same relacionalne baze. RDBMS predstavljaju podatke u tabelarnom formatu dok OO jezici, kao Java ili C# predstavljaju podatke kao graf objekata. Pogledajmo primer jedne Java klase: public class Employee { private int ID; private String first_name; private String last_name; private int salary; public Employee() {} public Emlpoyee (String fname, String lname, int salary) { this.first_name = fname; this.last_name = lname; this.salary = salary; }
6
Poglavlje 1 Objektno Relaciono Mapiranje (ORM)
public int getID() {return ID;} public String getFirstNsme() { return first_name; } public String getLastName() { return last_name; } public int getSalary() {return salary;} }
Da bismo mogli da sačuvamo objekte prethodno date klase neophodna bi nam bila tabela: CREATE TABLE employee ( id INT NOT NULL AUTO_INCREMENT, first_name VARCHAR(20) defailt NULL, last_name VARCHAR(20) defailt NULL, salary INT defalut NULL, PRIMARY KEY (id) );
ZAŠTO ORM - VIDEO Kratak video uvod u ORM Ova lekcija sadrži video materijal. Ukoliko želite da pogledate ovaj video morate da otvorite LAMS lekciju.
PROBLEMI I PREDNOSTI ORM-A Objektno-relaciono mapiranje je rešenje problema kao što su: granularnost, nasleđivanje, različito predstavljanje asocijacija, navigacija Najveći problem je što svaki put kad želimo da izmenimo nešto u aplikaciji moramo da menjamo dva dela aplikacije. Pored ovoga javljaju se i sledeći problemi: 1. Granularnost - Često ćemo imati više objekata nego tabela u bazi 2. Nasleđivanje - RDBMS-i ne definišu sličnosti kao nasleđivanje 3. Identitet - RDBMS definiše taćno jedan identiet, dok u Javi postoje dve vrste jednakosti: logička i fizička 4. Asocijacije - OO jezici predstavljaju asocijacije korišćenjem referenci, dok RDBMS-ovi predstavljau asocijacije korišćenjem stranih ključeva 5. Navigacija - Načini na kojima se objektima pristupa u Javi i RDBMS-ovima je fudamntalno drugačiji
7
Poglavlje 1 Objektno Relaciono Mapiranje (ORM)
Objektno-relaciono mapiranje (ORM) je rešenje problema koji su prethodno predstavljeni. ORM predstavlja tehnologiju programiranja za konverziju podataka između relacioninih baza podataka i objektno orijentisanih programskih jezika. Prednosti ORM-a: 1. 2. 3. 4. 5. 6. 7.
Biznis logika aplikacije ne mora da koristi DB tabele SQL upiti su sakriveni od OO logike Enkapsulira JDBC Ne bavi se implemtacijom baza Entiteti su radije bazirani na biznis logici nego na strukturi baze Transakcioni menadzment Brz razvoj aplikacija
ORM TUTORIJAL Kratak video tutorijal koji uvodi u objetno-relaciono mapiranje Ova lekcija sadrži video materijal. Ukoliko želite da pogledate ovaj video morate da otvorite LAMS lekciju.
8
Poglavlje 2 Java ORM (Hibernete) RAZLIKE IZMEĐU JPA I HIBERNATE-A - VIDEO Kratak video zapis koji objašnjava osnovne razlike između JPA i Hibernate-a Ova lekcija sadrži video materijal. Ukoliko želite da pogledate ovaj video morate da otvorite LAMS lekciju.
FRAMEWORK-OVI ZA ORM U JAVI Postoji puno framework-ova za ORM u Javi: Castor, TopLink i Hibernate Postoji puno framework-ova za ORM u Javi. • Castor • TopLink • Hibernate Hibernate arhitektura je napravljena tako da ne zavisi od API-a koji koristimo. Hibernate koristi bazu i konfiguraciju kako bi omogućio svoje servise aplikaciji. Persistance framework je ORM servis koji skladišti i vraća objekte iz relacionih baza:
9
Poglavlje 2 Java ORM (Hibernete)
Slika 2.1.1 Arhitektura Hibernete-a sa bitnim klasama
Hibernate koristi različite Java biblioteke kaošto su JDBC, Java Transaction API (JTA), i Java Naming and Directory Interface (JNDI). JDBC omogućava osnovni nivo abstrakcije funkcionalnosti česte za relacione baze podataka. Podržanost skoro bilo koje baze sa JDBC driverom omogućava podršku Hibernate-a. JNDI i JTA dozvoljavaju Hibernate-u da bude integrisan sa J2EE aplikacionim serverom.
10
Poglavlje 2 Java ORM (Hibernete)
Slika 2.1.2 Hibernate koristi različite objekte i Java biblioteke kao što su JDBC, JTA i JNDI
OBJEKTI HIBERNET-A: OBJEKAT KONFIGURACIJE I SESSIONFACTORY OBJEKAT Objekat konfiguracije omogućava konfiguraciju ili potrebna podešavanja u Hibernate-u i koristi se za pravljenje SessionFactory objekta Objekat konfiguracije: Konfiguracioni objekat ili objekat konfiguracije je obično prvi Hibernate objekat koji se kreira u Hibernate aplikaciji i obično se pravi samo na početnom pokretanju aplikacije. Omogućava konfiguraciju ili podešavanja potrebna u Hibernate-u.Konfiguracioni objekat omogućava dve ključne komponente: 1. 2. 3. 4.
Konekciju na bazu: hibernate.properties hibernate.cfg.xml. Class Mapping Setup
SessionFactory Objekat:
11
Poglavlje 2 Java ORM (Hibernete)
Objekat konfiguracije se koristi za pravljenje SessionFactory objekta koji konfiguriše Hibernate u aplikaciji korišćenjem objekta konfiguracije koji mu prosledimo. SessionFactory je višenitno bezbedan objekat i koristi se od strane više niti u aplikaciji. SessionFactory je težak objekat tako da se obično pravi samo početkom aplikacije i čuva za posle. Ukoliko vaša aplikacija radi sa više od jedne baze biće potrebno više SessionFactory objekata, jedan po bazi.
OBJEKTI HIBERNET-A: SESSION OBJEKAT, TRANSACTION OBJEKAT, QUERY OBJEKAT, CRITERIA OBJEKAT Ovi objekti imaju uloge da omoguće fizičku konekciju sa bazom, korišćenjem SQL ili HQL String-ova uzimaju podatke iz baze, kreiraju i izvršavaju objektno orijentisane upite itd. Session Objekat: Session objekat ili sesija sa bazom nam omogućava fizičku konekciju sa bazom. Session objekat je lagan i dizajniran je da bude instanciran svaki put kad je interakcija sa bazom potrebna. Objekte koje čuvamo u bazu čuvamo kroz Session objekat. Session objekat ne treba da postoji predugo i obično nije thread safe. Transaction Objekat: Objekat transakcije predstavlja jedan kokretan posao za rad nad bazomi većina RDBMS-a podržava transakcije. Transakcije u hibernate-u idu kroz transakcioni menadžer i transakcije (iz JDBC-a ili JTA-a). Query Objekat: Query objekatkoristi SQL ili HQL String-ove za uzimanje podatke iz baze.Query instanca se koristi za bind-ovanje upitnih parametara i limitiranje broja rezultata koje upit vraća. Criteria Objekat: Criteria objekat se koristi za kreiranje i izvršavanje objektno orijentisanih upita koji vraćaju objekte kao rezultat. Hibernate zahteva da unapred zna gde može da nađe podatke o mapiranju java klasa u relacionu bazu podataka. Hibernate takođe zahteva skup konfiguracionih podešavanja vezanih za bazu i druge parametre. Sve te informacije se obično dostavljaju u Java properties file-u hibernate.properties ili kao deo XML file-a koji se zove hibernate.cfg.xml.
koji
se
zove
12
Poglavlje 2 Java ORM (Hibernete)
HIBERNATE PODEŠAVANJA (HIBERNATE.PROPERTIES) Lista property-ja i njihov opis Lista property-ja i njihov opis:
Slika 2.1.3 Lista property-ja i njihov opis
HIBERANTE VIDEO TUTORIJAL Uvod u Hibernate - video tutorijali Ova lekcija sadrži video materijal. Ukoliko želite da pogledate ovaj video morate da otvorite LAMS lekciju. Ova lekcija sadrži video materijal. Ukoliko želite da pogledate ovaj video morate da otvorite LAMS lekciju.
13
Poglavlje 2 Java ORM (Hibernete)
2.1 Hibernate sa MySQL bazom PRIMER HIBERNATE.CFG.XML FILE-A File se postavlja u root direktorijum aplikacije Da bi smo specificirali hibernate podešavanja iz primera u daljem tekstu će se koristiti hibernate.cfg.xml. Ukoliko ih eksplicitno ne podesimo, većina parametara uzima predodređene vrednosti. Ovaj file se čuva u root direktorijumu našeg projekta. Napravićemo jedan hibernate.cfg.xml file i postaviti ga u root direktorijum naše aplikacije. Potrebno je da napravimo testdb bazu podataka dostupnu našoj MySQL instalaciji. Tagove <mapping> koristimo da bi smo hibernate-u označili koje file-ove koristimo za mapiranje.
<sesion-factory> <property name="hiberante.dialect"> org.hibernate.dialect.MySQLDialect <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver <property name="hibernate.connection.url"> jdbc:mysql://localhost/test <property name="hibernate.connection.username"> root <property name="hibernate.connection.password"> root123 <mapping resource="Employee.hbm.xml"/>
PRIMERI DIALEKATA ZA RAZLIČITE RDBMS-E Dialekt je jedan od parametara koji se definiše u hibernate.cfg.xml fileu
14
Poglavlje 2 Java ORM (Hibernete)
Slika 2. Različite vrste dialekata i način na koji se oni definišu u hibernate.cfg.xml file-u
Slika 2.2.1 Različite vrste dialekata i način na koji se oni definišu u hibernate.cfg.xml file-u - Nastavak
KONEKCIJA SA BAZOM Fizička konekcija sa bazom se ostvaruje preko session objekta 15
Poglavlje 2 Java ORM (Hibernete)
Session objekat je lagan i instancira se svaki put kada nam je potrebna interakcija sa bazom. Perzistentni objekti se čuvaju u bazi kroz Session objekat. Session objekat ne bi trebalo da postoji dugo, jer obično nije thread safe i trebalo bi da bude uništen kada više ne bude potreban. Osnovne funkcije sesije su da omogući čitanje, brisanje, izmenjivanje i listanje mapiranih klasa. Svaki objekat u bazi može da bude u tri stanja: • Transient • Persistent • Detached Operacije sesije bacaju grešku ukoliko je baza bacila grešku, u ovom slučaju celu transakciju je dobro vratiti unazad (nijedna od izmena u transakciji neće biti izvršena).
METODE SESSION INTERFACE-A Postoji puno metoda koje Session interface obezbeđuje, ali ovde ćemo pomenuti samo najbitnije.
Slika 2.2.2 Metode session objekta
16
Poglavlje 2 Java ORM (Hibernete)
Slika 2.2.3 Metode session objekta-nastavak1
METODE SESSION INTERFACE-A - NASTAVAK Postoji puno metoda koje Session interface obezbeđuje, ali ovde ćemo pomenuti samo najbitnije - nastavak.
Slika 2.2.4 Metode session objekta-nastavak2
17
Poglavlje 2 Java ORM (Hibernete)
Slika 2.2.5 Metode session objekta-nastavak3
HIBERNATE ANOTACIJE Koriste se kako bismo hibernate-u objasnili kako da mapira naše klase Hibernate anotacije su način za obezbeđivanje meta podatke vezanih za java klasu kako bi se omogućilo da java file-ovi jasno i jedinstveno budu mapirani u bazu podataka. Environment Setup for Hibernate Annotation Potrebne biblioteke su • hibernate-annotations.jar, • lib/hibernate-comons-annotations.jar • lib/ejb3-persistence.jar Primer anotirane klase i tabele koja joj parira CREATE TABLE employee ( id INT NOT NULL AUTO_INCREMENT, first_name VARCHAR(20) default NULL, last_name VARCHAR(20) default NULL, salary INT defalut NULL, PRIMARY KEY (id) );
EMPLOYEE KLASA SA ANOTACIJAMA ZA MAPIRANJE DEFINISANE TABELE @Id anotacija je vezana za polja tabele
18
Poglavlje 2 Java ORM (Hibernete)
import javax.persistance.*; @Entity @Table (name = "Employee") public class Employee { @Id @GeneratedValue @Comlumn(name = "id") private int id; @Comlumn(name = "first_name") private String firstName; @Comlumn(name = "last_name") private String lastName; @Comlumn(name = "salary") private int salary; public Employee() {} public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; }}
19
Poglavlje 2 Java ORM (Hibernete)
@Id anotacija je vezana za polja tabele što znači da se property-ju jednog objekta može pristupiti direktno kroz polja u tabeli za vreme izvršavanja programa (runtime). Ako @Id anotaciju postavimo iznad getId() metode, podrazumeva se da property-ima pristupamo kroz metode getera i setera.
ANOTACIJE KORIŠĆENE U KLASI EMPLOYEE – I DEO @Entity anotacija, @Table anotacija, @Id anotacija, @GeneratedValue anotacija @Entity anotacija: EJB 3 standardne anotacije se nalaze u okviru javax.persistence paketa, tako da je naš prvi korak import-ovanje ovog paketa. Dalje koristimo @Entity anotaciju nad Employee klasom što označava da je ova klasa entity bean, što znači da ona mora da ima konstruktor bez argumenata kako bi bila vidljiva najmanje u okviru protected domena. @Table anotacija: @Table anotacija nam omogućava da definišemo detalje koji se tiču tabele koja se koristi za persist-ovanje entiteta u bazi podataka. @Table anotacija obezbeđuje četiri atribtua, tako da nam omogućava da nadjačamo (override) naziv tabele, njen katalog, njenu šemu i da sprovedemo jedinstvena ograničenja (constraints) nad kolonama u tabeli. Za sada koristimo samo naziv tabele, tj. EMPLOYEE. @Id anotacija: Svaki entity bean ima svoj primarni ključ koji definišemo nad samom klasom uz pomoć @Id. Primarni ključ može biti jedno polje ili kombinacija više polja što zavisi od strukture tabele. Podrazumevano, @Id anotacija automatski određuje najprikladniju strategiju za odabir primarnog ključa generacije, ali to možemo nadjačati tako što postavimo @GeneratedValue anotacija: Prima dva parametra strategy i generator, ali o tome ovde neće biti reči, tako da ćemo koristiti strategiju podrazumevanog ključa. Time što dozvoljavamo Hibernate-u da sam odluči koji će tip generisanja da koristi čini naš kod lako prenosivim između različitih baza podataka.
ANOTACIJE KORIŠĆENE U KLASI EMPLOYEE – II DEO @Column anotacija @Column anotacija: @Column anotacija se koristi kada želimo da definišemo detalje neke kolone nad koje će biti mapirano polje ili property. Možemo koristiti anotaciju kolone sa sledećim, najčešće korišćenim atributima:
20
Poglavlje 2 Java ORM (Hibernete)
• name atribut dozvoljava da se eksplicitno definiše ime kolone. • length atribut dozvoljava definisanje veličine kolone koja se koristi da mapira vrednost konkretno za neku String vrednost. • nullable atribut dozvoljava koloni da bude obeležena sa NOT NULL onda kada je generisana šema. • unique atribut dozvoljava koloni da bude obeležena tako da čuva samo jedinstvene (unique) vrednosti.
KREIRANJE KLASE APLIKACIJE Početak klase Konačno, treba kreirati klasu aplikacije sa main() metodom koja pokreće aplikaciju. Ovu aplikaciju ćemo koristiti kako bismo sačuvali nekoliko Employee zapisa, nad kojim će kasnije biti primenjene CRUD operacije. import import import import import import import import import
java.util.List; java.util.Date; java.util.Iterator; org.hibernate.HibernateException; org.hibernate.Session; org.hibernate.Transsaction; org.hibernate.cfg.AnnotationConfiguration; org.hibernate.SessionFactory; org.hibernate.cfg.Configuration;
public class ManageEmployee { private static SessionFactory factory; public static void main(String[] args) { try{ factory = new AnnotationConfiguration().configure(). // addPackage("com.xyz") //add package if used addAnnotatedClass(Employee.class).buildSessionFactoru(); } catch (Throwable ex) { System.err.println("Faild to create sessionFactoru object" + ex); throw new ExceptionInInitializerError(ex); ManageEmployee ME = new ManageEmployee();
KLASE APLIKACIJE – I DEO Dodavanje nekoliko Employee zapisa /* Add few employee Integer Integer Integer
records in database*/ empID1 = ME.addEmployee("Zara", "Ali", 1000); empID2 = ME.addEmployee("Daisy", "Das", 5000); empID3 = ME.addEmployee("John", "Paul", 10000);
21
Poglavlje 2 Java ORM (Hibernete)
/* List down all the employee*/ ME.listEmployees(); /* Update employee's records*/ ME.updateEmployee(empID1, 5000); /* Delete an employee from the database*/ ME.deleteEmployee (empID2); /* List down new list the employee*/ ME.listEmployees(); } }
KLASE APLIKACIJE – II DEO Metoda za dodavanje novog zaposlenog /* Method to CREATE an employee in database */ public Integer addEmployee(String fname, String lname, int salary) { Session session = factory.openSession(); Transaction tx = null; Integer employeeID = null; try{ tx = session.beginTransaction(); Employee employee = new ManageEmployee(); employee.setFirstName(fname); employee.setLastName(lname); employee.setSalary(salary); employeeID = (Integer) session.save(employee); tx.commit(); } catch (HibernateException e){ if (tx != null) tx.rolback(); e.printStackTrace(); } finally { session.close(); } return employeeID; }
KLASE APLIKACIJE – III DEO Metoda za listanje zaposlenih
22
Poglavlje 2 Java ORM (Hibernete)
/* Method to READ all the employees in database */ public void listEmployees() { Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); List employees = session.createQuery("FROM Empolyee").list(); for (Iterator iterator = employees.iterator(); iterator.hasNext(); ){ Employee employee = (Employee) iterator.next(); System.out.println("First Name: " + employee.getFirstName()); System.out.println("Last Name: " + employee.getLastName()); System.out.println("Salsry: " + employee.getSalary()); } tx.commit(); } catch (HibernateException e){ if (tx != null) tx.rolback(); e.printStackTrace(); } finally { session.close(); } }
KLASE APLIKACIJE – IV DEO Metoda za ažuriranje zaposlenih /* Method to UPDATE salary for employee */ public void updateEmployee(Integer EmployeeID, int salary){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Employee employee = (Employee) session.get(Employee.class, EmployeeID); employee.setSalary(salary); session.update(employee); tx.commit(); } catch (HibernateException e){ if (tx != null) tx.rolback(); e.printStackTrace(); } finally { session.close(); }
23
Poglavlje 2 Java ORM (Hibernete)
}
KLASE APLIKACIJE – V DEO Metoda za brisanje zaposlenih /* Method to DELETE employee */ public void deleteEmployee(Integer EmployeeID){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Employee employee = (Employee) session.get(Employee.class, EmployeeID); session.delete(employee); tx.commit(); } catch (HibernateException e){ if (tx != null) tx.rolback(); e.printStackTrace(); } finally { session.close(); } } }
HIBERNATE.CFG.XML KONFIGURACIONI FAJL Sadržaj parametre vezane za bazu Sada ćemo da kreiramo hibernate.cfg.xml konfiguracioni fajl kako bismo definisali parametre vezane za bazu.
<sesion-factory> <property name="hiberante.dialect"> org.hibernate.dialect.MySQLDialect <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver
24
Poglavlje 2 Java ORM (Hibernete)
<property name="hibernate.connection.url"> jdbc:mysql://localhost/students <property name="hibernate.connection.username"> root <property name="hibernate.connection.password"> root321
KOMPAJLIRANJE I IZVRŠAVANJE APLIKACIJE Koraci za kompajliranje U nastavku su dati koraci za kompajliranje i izvršavanje ranije pomenute aplikacije. Pre nego što se nastavi sa kompajliranjem i izvršavanjem aplikacije treba proveriti da li su pravilno postavljene promenljive PATH i CLASSPATH. Izbrisati Employee.hbm.xml fajl za mapiranje sa putanje. Kreirati Employee.java izvorni fajl kako je na slici 8. i kompajlirati ga. Izvršiti ManageEmployee binary kako biste pokrenuli program. $java ManageEmployee .......VARIOUS LOG MESSAGES WILL DISPLAY HERE....... First Name: Zara Last Name: Ali Salary: 1000 First Name: Daisy Last Name: Das Salary: 5000 First Name: John Last Name: Paul Salary: 10000 First Name: Zara Last Name: Ali Salary: 5000 First Name: John Last Name: Paul Salary: 10000
Slika 8. Employee.java izvorni fajl Kao rezultat se dobija se sledeći sadržaj tabele Employee mysql> select * from EMPLOYEE; +----+------------+-----------+--------+ | id | first_name | last_name | salary | +----+------------+-----------+--------+ | 29 | Zara | Ali | 5000 | | 31 | Daisy | Das | 10000 | +----+------------+-----------+--------+ 2 rows in set (0.00 sec) mysql>
25
Poglavlje 3 Hibernate Query Language (HQL) ŠTA JE HIBERNATE QUERY LANGUAGE (HQL) ? Objektno orijentisan jezik za upite, sličan SQL-u, ali umesto što izvršava operacije nad tabelama i kolonama, HQL radi sa perzistentnim objektima i njihovim property-ima HQL upiti se prevode od strane Hibernate-a u konvencionalne SQL upite koji onda izvršavaju zadate akcije nad bazom podataka. Iako možemo da koristimo SQL iskaze direktno u Hibernate-u upotrebom Native SQL, ipak preporučujemo korišćenje HQL-a kada god je to moguće kako bismo izbegli problem koji se javljaju prilikom prenosa baze podataka, i kako bismo iskoristili Hibernate SQL strategije generacija i keširanja. U HQL-u, ključne reči poput SELECT, FROM i WHERE itd. nisu case sensitive, ali property-ji poput tabela i naziva kolona jesu case sensitive.
FROM I AS KLAUZULA FROM koristimo kada želimo da učitamo kompletne perzistentne objekte u memoriju dok se AS kaluzula oristi se za dodeljivanje pseudonima (alias) klasama u HQL upitima Ispod je data jednostavna sintaksa u kojoj se koristi FROM klauzula: String hql = "FROM Employee"; Query query = session.createQuery(hql); List results = query.list();
Ako nam je potrebno da u potpunosti kvalifikujemo ime klase u HQL-u, potrebno je samo definisati paket ili ime klase kao što je dato u nastavku: String hql = "FROM com.hibernatebook.criteria.Employee"; Query query = session.createQuery(hql);
26
Poglavlje 3 Hibernate Query Language (HQL)
List results = query.list();
AS klauzula se koristi se za dodeljivanje pseudonima (alias) klasama u HQL upitima, posebno ako imamo duge upite Npr. u prethodnom primeru to bi izgledalo ovako: String hql = "FROM Employee AS E"; Query query = session.createQuery(hql); List results = query.list();
AS ključna reč je opciona, a takođe možemo definisati alias direktno nakon imena klase, kao što je dato: String hql = "FROM Employee E"; Query query = session.createQuery(hql); List results = query.list();
SELECT I WHERE KLAUZULA SELECT klauzula obezbeđuje više kontrole nad rezultatom nego što to pruža from klauzula. Ako želimo da suzimo konkretne objekte koji se iščitavaju iz baze, koristimo WHERE klauzulu Ako želimo da iščitamo nekoliko property-ja objekata umesto kompletnog objekta, koristimo SELECT klauzulu. I spod je prikazana jednostavna sintaksa gde se koristi SELECT klauzula kako bi se izvuklo samo polje first_name iz objekta Employee: String hql = "SELECT E.firstName FROM Employee E"; Query query = session.createQuery(hql); List results = query.list();
Primetićemo da je ovde Employee.firstName ustvari property objekta Employee, a ne polje EMPLOYEE tabele. Sledi primer sintakse gde se koristi WHERE klauzula: String hql = "FROM Employee E WHERE E.id = 10"; Query query = session.createQuery(hql);
27
Poglavlje 3 Hibernate Query Language (HQL)
List results = query.list();
ORDER BY KLAUZULA Za sortiranje rezultata našeg HQL upita, potrebno je da koristimo BY klauzulu Za sortiranje rezultata našeg HQL upita, potrebno je da koristimo BY klauzulu. Moguće je sortirati rezultate prema bilo kom property-ju iz upotrebljenog seta objekata u rastućemascending (ASC) ili opadajućem-descending(DESC) redosledu. Dat je jednostavan primer sa sintaksom koja koristi ORDER BY klauzulu: String hql = "FROM Employee E WHERE E.id > 10 ORDER BY E.salary DESC"; Query query = session.createQuery(hql); List results = query.list();
Ako želimo da sortiramo više od jednog property-ja, potrebno je da samo dodamo dodatne property-je na kraj order by klauzule, tako što ih razdvojimo zarezom kako je prikazano: String hql = "FROM Employee E WHERE E.id > 10 " + "ORDER BY E.firstName DESC, E.salary DESC "; Query query = session.createQuery(hql); List results = query.list();
GROUP BY KLAUZULA Ova klauzula omogućava Hibernate-u da povuče informacije iz baze podataka i da ih grupiše na osnovu vrednosti nekog atributa Tipično, taj rezultatse koristi kako bi se dobila objedinjena vrednost (aggregate value). Dat je primer sintakse sa GROUP BY klauzulom: String hql = "SELECT SUM(E.salary), E.firtName FROM Employee E " + "GROUP BY E.firstName"; Query query = session.createQuery(hql); List results = query.list();
28
Poglavlje 3 Hibernate Query Language (HQL)
Hibernate podržava imenovane parameter u svojim HQL upitima. Ovo čini pisanje HQL upit koji primaju unos od strane korisnika veoma lakim, pri čemu ne moramo da razmišljamo kako da se odbranimo od SQL injection napada. Sledi jednostavna sintaksa koja koristi imenovane parametre: String hql = "FROM Employee E WHERE E.id = :employee_id"; Query query = session.createQuery(hql); query.setParameter("employee_id",10); List results = query.list();
UPDATE, DELETE I INSERT KLAUZULA Može se koristiti za ažuriranje, brisanje ili unošenje jednog ili više property-ja jednog ili više objekata Interfejs za upite sada sadrži metod koji se zove executeUpdate() koji služi za izvršavanje HQL UPDATE ili DELETE iskaza. Prikazana je sintaksa sa upotrebom UPDATE klauzuleispod: String hql = "UPDATE Employee SET salary = :salary " + "WHERE id = :employee_id"; Query query = session.createQuery(hql); query.setParameter("salary", 1000); query.setParameter("employee_id", 10); int result = query.executeUpdate(); System.out.println("Rows affected: " + result);
DELETE klauzula se može koristiti za brisanje jednog ili više objekata. Data je jednostavna sintaksa sa DELETE klauzulom: String hql = "DELETE FROM Employee " + "WHERE id = :employee_id"; Query query = session.createQuery(hql); query.setParameter("employee_id", 10); int result = query.executeUpdate();
29
Poglavlje 3 Hibernate Query Language (HQL)
System.out.println("Rows affected: " + result);
HQL podržava INSERT INTO klauzulu samo onde gde zapisi mogu biti umetnuti iz jednog u drugi objekat. Sledi sintaksa sa primerom korišcenja INSERT INTO klauzule: String hql = "INSERT INTO Employee(firstName, lastName, salary)" + "SELECT firstName, lastName, salary FROM old_employee"; Query query = session.createQuery(hql); int result = query.executeUpdate(); System.out.println("Rows affected:" + result);
SUMARNE (AGGREGATE) METODE I KLAUZULA DISTINCT Sumarne metode u HQL-u rade na isti način kao i u SQL-u. Ključna reč distinct izdvaja jedinstvene vrednosti neke kolone HQL podržava određen spektar sumarnih metoda, slično kao i SQL. Oni rade na isti način u HQL-u kao i u SQL-u. U tabeli 1. je dat spisak dostupnih funkcija: 1. avg(property name) - Srednja vrednost propertyja 2. count(property name or *) - Broj puta koliko se property ponavlja u rezultatu 3. max(property name) - Maksimalna vrednost među property vrednostima 4. min(property name) - Minimalna vrednost među property vrednostima 5. sum(property name) - Ukupna suma property vrednosti Ključna reč distinct broji jedinstvene vrednosti u jednom redu. Sledeći upit će vratiti samo broj jedinstvenih vrednosti: String hql = "SELECT COUNT(DISTINCT E.firstName) FROM Employee E"; Query query = session.createQuery(hql);
30
Poglavlje 3 Hibernate Query Language (HQL)
List results = query.list();
HQL VIDEO TUTORIJAL Kratak uvod u HQL - video tutorijal Ova lekcija sadrži video materijal. Ukoliko želite da pogledate ovaj video morate da otvorite LAMS lekciju. Ova lekcija sadrži video materijal. Ukoliko želite da pogledate ovaj video morate da otvorite LAMS lekciju.
HQL VIDEO TUTORIJAL 2 Ne tako kratak uvod u HQL - video tutorijal Ova lekcija sadrži video materijal. Ukoliko želite da pogledate ovaj video morate da otvorite LAMS lekciju.
3.1 Paginacija korišćenjem Query-a METODE QUERY INTERFEJSA KOJE OMOGUĆAVAJU PAGINACIJU Postoje dve metode: QuerysetFirsResult i QuerysetMaxResult Postoje dve metode Query interfejsa koje nam omogućavaju paginaciju: 1. Query setFirstResult(int startPosition) - Metoda uzima int koji predstavlja prvi red koji treba da se vrati iz rezultata 2. Query setMaxResults(int maxPosition) - Metoda ograničava broj rezultata koje će upit da vrati Zajedničkom upotrebom ova dva navedena metoda, možemo da konstruišemo komponentu za paginaciju na našoj veb ili Swing aplikaciji. Prikazan je primer koji čita podatke iz tabele i prikazuje samo 10 redova u datom trenutku: String hql = "FROM Employee"; Query query = session.createQuery(hql); query.setFirstResult(1);
31
Poglavlje 3 Hibernate Query Language (HQL)
query.setMaxResults(10); List results = query.list();
PAGINACIJA METODOM CRITERIA API Metoda Criteria API nam dozvoljava da programski izgradimo criteria query objekat gde možemo da primenimo pravila za filtriranje i logičke uslove. Hibernate obezbeđuje alternativne načine manipulisanja objektima i za uzvrat vraća podatke dostupne u RDBMS tabelama. Hibernate Session interfejs obezbeđuje metod createCriteria() koji se može koristiti za kreiranje Criteria objekta koji vraća instance klase tog perzistentnog objekta onda kada aplikacija izvrši criteria upit. Sledi najjednostavniji primer criteria upita koji jednostavno vraća svaki objekat koji odgovara klasi Employee. Criteria cr = session.createCriteria(Employee.class); List results = cr.list();
OGRANIČENJA SA KRITERIJUMIMA Kako bismo dodali ograničenja nad criteria upitom koristi se add() metod koji je dostupan za Criteria objekte Sledi primer gde se dodaje ograničenje za prikazivanje samo onih zapisa gde je plata radnika jednaka 2000: Criteria cr = session.createCriteria(Employee.class); cr.add(Restrictions.eq("salary", 2000)); List results = cr.list();
Navedeni su još neki primeri koji pokrivaju više različitih scenarija i koji se mogu koristiti po potrebi: Criteria cr = session.createCriteria(Employee.class); // To get records having salary more than 2000 cr.add(Restrictions.gt("salary", 2000));
32
Poglavlje 3 Hibernate Query Language (HQL)
// To get records having salary less than 2000 cr.add(Restrictions.lt("salary", 2000)); // To get records having fistName starting with zara cr.add(Restrictions.like("firstName", "zara%")); // Case sensitive form of the above restriction. cr.add(Restrictions.ilike("firstName", "zara%")); // To get records having salary in between 1000 and 2000 cr.add(Restrictions.between("salary", 1000, 2000)); // To check if the given property is null cr.add(Restrictions.isNull("salary")); // To check if the given property is not null cr.add(Restrictions.isNotNull("salary")); // To check if the given property is empty cr.add(Restrictions.isEmpty("salary")); // To check if the given property is not empty cr.add(Restrictions.isNotEmpty("salary"));
KREIRANJE AND ILI OR USLOVA AND i OR uslovi se kreiraju korišćenjem LogicalExpression ograničenja Ograničenja se kreiraju na sledeći način: Criteria cr = session.createCriteria(Employee.class); Criterion salary = Restrictions.gt("salary", 2000); Criterion name = Restrictions.ilike("firstNname","zara%"); // To get records matching with OR condistions LogicalExpression orExp = Restrictions.or(salary, name); cr.add( orExp ); // To get records matching with AND condistions LogicalExpression andExp = Restrictions.and(salary, name); cr.add( andExp ); List results = cr.list();
33
Poglavlje 3 Hibernate Query Language (HQL)
SORTIRANJE REZULTATA Koristi se org.hibernate.criterion.Order klasa koja služi za sortiranje rezultata ili u rastućem ili u opadajućem redosledu Sledeći primer prikazuje kako bismo iskoristili Order klasu za sortiranje rezultata: Criteria cr = session.createCriteria(Employee.class); // To get records having // salary more than 2000 cr.add(Restrictions.gt("salary", 2000)); // To sort records in descening order crit.addOrder(Order.desc("salary")); // To sort records in ascending order crit.addOrder(Order.asc("salary")); List results = cr.list();
PROJEKCIJE I AGREGACIJE Criteria API pruža org.hibernate.criterion.Projections klasu koja se koristi za dobijanje prosečne, maksimalne i minimalne vrednosti property-ja. Projections klasa je slična Restrictions klasi u smislu da obezbeđuje nekoliko statičkih factory metoda za dobavljanje Projection instanci. Navedeno je nekoliko primera koji pokrivaju različite scenarije i koji se mogu koristiti po potrebi: Criteria cr = session.createCriteria(Employee.class); // To get total row count. cr.setProjection(Projections.rowCount()); // To get average of a property. cr.setProjection(Projections.avg("salary")); // To get distinct count of a property. cr.setProjection(Projections.countDistinct("firstName"));
34
Poglavlje 3 Hibernate Query Language (HQL)
// To get maximum of a property. cr.setProjection(Projections.max("salary")); // To get minimum of a property. cr.setProjection(Projections.min("salary")); // To get sum of a property. cr.setProjection(Projections.sum("salary"));
35
Poglavlje 4 Vežba: Pisanje Java koda uz pomoć Hibernate-a DEFINICIJA JAVE KLASE Java klasa Employee; Uzmimo u obzir sledecu POJO klasu: public class Employee { private private private private
int id; String firstName; String lastName; int salary;
public Employee() {} public Employee(String fname, String lname, int salary) { this.firstName = fname; this.lastName = lname; this.salary = salary; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } }
DEFINICIJA RELACIONE TABELE Relaciona tabela Employee Kreiraćemo sledeću EMPLOYEE tabelu za cuvanje Employee objekata:
36
Poglavlje 4 Vežba: Pisanje Java koda uz pomoć Hibernate-a
create table EMPLOYEE ( id INT NOT NULL auto_increment, first_name VARCHAR(20) default NULL, last_name VARCHAR(20) default NULL, salary INT default NULL, PRIMARY KEY (id) );
FAJL ZA MAPIRANJE. Fajl za mapiranje definiše način mapiranja relacione tabele i java klase Ispod je dat fajl za mapiranje.
<meta attribute="class-description"> This class contains the employee detail. <property name="firstName" column="first_name" type="string"/> <property name="lastName" column="last_name" type="string"/> <property name="salary" column="salary" type="int"/>
JAVA PROGRAMSKI KOD-I DEO Importovanje klasa Hibernete-a i dodavanje redova u relacionu tabelu import import import import import import import import
java.util.List; java.util.Date; java.util.Iterator; org.hibernate.HibernateException; org.hibernate.Session; org.hibernate.Transaction; org.hibernate.SessionFactory; org.hibernate.Criteria;
37
Poglavlje 4 Vežba: Pisanje Java koda uz pomoć Hibernate-a
import org.hibernate.criterion.Restrictions; import org.hibernate.criterion.Projections; import org.hibernate.cfg.Configuration; public class ManageEmployee { private static SessionFactory factory; public static void main(String[] args) { try{ factory = new Configuration().configure().buildSessionFactory(); }catch (Throwable ex) { System.err.println("Failed to create sessionFactory object." + ex); throw new ExceptionInInitializerError(ex); } ManageEmployee ME = new ManageEmployee(); /* Add few employee records in database */ Integer empID1 = ME.addEmployee("Zara", "Ali", 2000); Integer empID2 = ME.addEmployee("Daisy", "Das", 5000); Integer empID3 = ME.addEmployee("John", "Paul", 5000); Integer empID4 = ME.addEmployee("Mohd", "Yasee", 3000); /* List down all the employees */ ME.listEmployees(); /* Print Total employee's count */ ME.countEmployee(); /* Print Toatl salary */ ME.totalSalary(); }
JAVA PROGRAMSKI KOD- II DEO Metoda za kreiranje employee u bazi podataka /* Method to CREATE an employee in the database */ public Integer addEmployee(String fname, String lname, int salary){ Session session = factory.openSession(); Transaction tx = null; Integer employeeID = null; try{ tx = session.beginTransaction(); Employee employee = new Employee(fname, lname, salary); employeeID = (Integer) session.save(employee); tx.commit(); } catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); }
38
Poglavlje 4 Vežba: Pisanje Java koda uz pomoć Hibernate-a
return employeeID; }
JAVA PROGRAMSKI KOD- III DEO Metoda za čitanje svih zaposlenih koji imaju platu veću od 2000 / * Method to READ all the employees having salary more than 2000 */ public void listEmployees( ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Criteria cr = session.createCriteria(Employee.class); // Add restriction. cr.add(Restrictions.gt("salary", 2000)); List employees = cr.list(); for (Iterator iterator = employees.iterator(); iterator.hasNext();){ Employee employee = (Employee) iterator.next(); System.out.print("First Name: " + employee.getFirstName()); System.out.print(" Last Name: " + employee.getLastName()); System.out.println(" Salary: " + employee.getSalary()); } tx.commit(); } catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } }
JAVA PROGRAMSKI KOD- IV DEO Metode za štampanje ukupnog broja slogova /* Method to print total number of records */ public void countEmployee(){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Criteria cr = session.createCriteria(Employee.class); // To get total row count.
39
Poglavlje 4 Vežba: Pisanje Java koda uz pomoć Hibernate-a
cr.setProjection(Projections.rowCount()); List rowCount = cr.list(); System.out.println("Total Coint: " + rowCount.get(0) ); tx.commit(); } catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } }
JAVA PROGRAMSKI KOD- V DEO Metoda za štampanje sume svih plata /* Method to print sum of salaries */ public void totalSalary(){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Criteria cr = session.createCriteria(Employee.class); // To get total salary. cr.setProjection(Projections.sum("salary")); List totalSalary = cr.list(); System.out.println("Total Salary: " + totalSalary.get(0) ); tx.commit(); } catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } } }
KOMPAJLIRANJE I IZVRŠAVANJE Koraci za kompajliranje i izvršavanje ranije pomenute aplikacije U nastavku su dati koraci za kompajliranje i izvršavanje ranije pomenute aplikacije. Proverite da li ste pravilno postavili PATH i CLASSPATH promenljive pre nego što nastavite sa kompajliranjem i izvršavanjem. • Kreirati hibernate.cfg.xml konfiguracioni fajl kako je objašenju u odeljku za konfiguraciju. • Kreirati Employee.hbm.xml fajl za mapiranje kao što je prikazano iznad.
40
Poglavlje 4 Vežba: Pisanje Java koda uz pomoć Hibernate-a
• Kreirati Employee.java izvorni fajl kako je prikazano iznad i kompajlirati ga. • Kreirati ManageEmployee.java izvorni fajl kako je prikazano iznad i kompajlirati ga. • Izvršiti ManageEmployee binary kako biste pokrenuli program. Dobićete sledeći rezultat, a zapisi će biti kreirani unutar EMPLOYEE tabele. $java ManageEmployee ....VARIOUS LOG MESSAGES WILL DISPLAY HERE.... First Name: Daisy Last Name: Das Salary: 5000 First Name: John Last Name: Paul Salary: 5000 First Name: Mohd Last Name: Yasee Salary: 3000 Total Coint: 4 Total Salary: 15000
Ako proverite EMPLOYEE tabelu, trebalo bi da sadrži sledeće zapise: mysql> select * from EMPLOYEE; +----+------------+-----------+--------+ | id | first_name | last_name | salary | +----+------------+-----------+--------+ | 14 | Zara | Ali | 2000 | | 15 | Daisy | Das | 5000 | | 16 | John | Paul | 5000 | | 17 | Mohd | Yasee | 3000 | +----+------------+-----------+--------+ 4 rows in set (0.00 sec) mysql>
4.1 Vežba: Keširanje ŠTA SE POSTIŽE KEŠIRANJEM? Keširanje optimizuje performance aplikacije Keširanje optimizuje performance aplikacije, tako da se nalazi između aplikacije i baze podataka, kako bi se što više izbegao broj pogodaka na bazu podataka i tako postigle bolje performance za aplikacije gde su one kritične. Keširanje je takođe bitno u Hibernate-u koji koristi šeme za keširanje na više nivoa, kako je objašnjeno u nastavku:
41
Poglavlje 4 Vežba: Pisanje Java koda uz pomoć Hibernate-a
Slika 4.1.1 Šeme keširanja u Hibernate-u
FIRST-LEVEL, SECOND-LEVEL I QUERY-LEVEL KEŠIRANJE Keširanje na prvom nivou je Session keširanje dok je keširanje na drugom nivou opciono; Query-level keširanje je takođe opciono i korisno za upite koji se često pokreću sa istim parame Keširanje na prvom nivouje Session keširanje i obavezno je jer svi zahtevi moraju proći kroz njega. Objekat sesije čuva objekat unutar sopstvene moći pre nego što ga komituje u bazu podataka. Ako pokrenete višestruko ažuiranje nad nekim objektom, Hibernate pokušava da odloži update što je duže moguće kako bi smanjio broj SQL iskaza za update koje su u opticaju. Ako zatvorite sesiju, svi objekti koji su bili keširani se gube ili su perzistovani ili ažurirani u bazi. Keširanje na drugom nivouje opciono, i pre nego što dođe do njega, uvek se prvo kontaktira keširanje prvog nivoa. Keširanje na drugom nivou može biti konfigurisan na dva načina: po klasi ili po kolekciji i generalno je odgovoran za keširanje objekata između sesija. Bilo koje keširanje sa treće strane se može koristiti Hibernate-u. Interfejs org.hibernate.cache.CacheProvider je obezbeđen, koji mora da bude implementiran kako bi omogučio Hibernate-u da izvrši implementaciju keširanje. Query-level keširanje: Hibernate takođe implementira keš za set rezultata upita koji se blisko integriše sa keširanjem na drugom nivou. Ovo je opciona funkcija i zahteva dva dodatna fizička keš regiona koji čuvaju keširane rezultate upita, kao i vremenske oznake kada je tabela poslednji put ažurirana. Ovo je jedino korisno za upite koji se često pokreću sa istim parametrima
42
Poglavlje 4 Vežba: Pisanje Java koda uz pomoć Hibernate-a
CONCURRENCY STRATEGIJE To je posrednik koji je odgovoran za smeštanje podataka u keš i preuzimanje istih iz keša. Ako se odlučimo da uključimo keširanje na drugom nivou, moramo da odlučimo, za svaku od perzistentnih klasa i kolekcija, koju ćemo strategiju paralelnog rada keša (cache concurrency) da koristimo. Transactional:Ovu strategiju koristimo kada učitavamo većinu podataka onde gde je kritično da sprečimo zastarele podatke u konkurentnim transakcijama, u retkim slučajevima ažuriranja. Read-write:Ovu strategiju takođe koristimo kada učitavamo većinu podataka onde gde je kritično da sprečimo zastarele podatke u konkurentnim transakcijama u retkim slučajevima ažuriranja. Nonstrict-read-write: Ova strategija ne garantuje konzistentnost između keša i baze podataka. Koristimo ovu strategiju onda kada se podaci veoma retko menjaju i kada mala verovatnoća zastarelih podataka nije od kritičnog interesa. Read-only: Strategija konkurencije koja je korisna za podatke koji se nikada ne menjaju. Koristimo je samo za referentne podatke. Ako želimo da iskoristimo keširanje na drugom nivou za našu Employee klasu, potrebno je da dodamo mapirajući element koji je potreban da bi smo Hibernate-u rekli da kešira Employee instance upotrebom read-write strategije. Atribut usage="read-write" govori Hibernate-u da koristi read-write strategiju konkurencije za definisan keš.
<meta attribute="class-description"> This class contains the employee detail. <property name="firstName" column="first_name" type="string"/> <property name="lastName" column="last_name" type="string"/> <property name="salary" column="salary" type="int"/>
CACHE PROVAJDERI Hibernate zahteva da odaberemo samo jednog keš provajedera za celu aplikaciju Naš sledeći korak koji razmatramo posto smo prikazali strategije konkurencije koje koristimo za naše klase koje su kandidati za keš, jeste odabir keš provajdera. Hibernate zahteva da odaberemo samo jednog keš provajedera za celu aplikaciju. 43
Poglavlje 4 Vežba: Pisanje Java koda uz pomoć Hibernate-a
Slika-
Svaki keš provajedr nije kompatibilan sa svakom concurrency strategijom. Sledeća matrica kompatibilnosti vam može moći da odaberete odgovarajuću kombinaciju.
Slika-
DEFINIŠEMO KEŠ PROVAJDERA Definiše se u okviru hibernate.cfg.xml konfiguracionog fajla U ovom slučaju biramo EHCache kao naš provajder za keširanje na drugom nivou:
<session-factory> <property name="hibernate.dialect"> org.hibernate.dialect.MySQLDialect <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver
44
Poglavlje 4 Vežba: Pisanje Java koda uz pomoć Hibernate-a
<property name="hibernate.connection.url"> jdbc:mysql://localhost/test <property name="hibernate.connection.username"> root <property name="hibernate.connection.password"> root123 <property name="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider <mapping resource="Employee.hbm.xml"/>
DEFINISANJE SVOJSTAVA KEŠ REGIONA Definišu se u sopstvenom konfiguarcionom fajlu, ehcache.xml EHCache ima sopstveni konfiguarcioni fajl, ehcache.xml, koji treba da se nalazi na CLASSPATH-u aplikacije. Keš konfiguracija u ehcache.xml za Employee klasu može da izgleda ovako:
<defaultCache maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" />
To je to, sada imamo uključeno keširanje na drugom nivou za klasu Employee i Hibernate sada pogađa keširanje na drugom nivou svaki put kada dođemo do Employee-a ili kada učitavamo Employee-a putem identifikatora. Treba analizirati svaku od klasa i odabrati odgovarajuću strategiju keširanja za svaku od njih. Ponekad, keširanje na drugom nivou može da smanji performanse aplikacije. Stoga je preporučljivo da se prvo radi na aplikaciji sa isključenim keširanjem, a tek kasnije treba uključiti odgovarajuće keširanje i proveriti performance. Ako keširanje ne poboljšava performanse sistema, onda nema smisla uključivati bilo koji tip keširanja.
45
Poglavlje 5 Domaći zadatak 14 UPUTSVA ZA RAD Uputstva Napomena: Rešeni zadatak šaljete kao SQL ili TXT fajl (arhiviran) na mail adresu asistenta. Studenti grupe u Beogradu i OnLine studenti zadatak na pregled šalju na mail
[email protected] Studenti iz Niša zadatak na pregled šalju na mail
[email protected] Prilikom slanja domaćeg zadatka svom asistentu neophodno je da ispunite sledeće: • Subject mail-a mora biti IT350-DZbr (u slučaju kada šaljete domaći za ovu nedelju to je IT350-DZ14) • U prilogu mail-a treba da se nalazi arhiviran projekat koji se ocenjuje imenovan na sledeci nacin: IT350-DZbr-ImePrezimeStudenta-BrojIndeksa. (Na primer, IT350-DZ14-VeljkoGrkovic-1234) • Telo mail-a treba da ima pozdravnu poruku • Svi poslati mail-ovi koji ne ispunjavaju navedene uslove NEĆE biti pregledavani. Za sva pitanja ili nedoumice u vezi zadatka, možete se obratiti asistentu.
TEKST ZADATKA Rešiti zadatak prema postavljenom tekstu 1. Kreirati bazu podataka NastavnikToPredmet sa sledecim 1. Tabela Nastavnik - sadrži osnovne podatke o nastavniku (ime, prezime, zvanje, ...) 2. Tabela Predmet - sadrži osnovne podatke o predmetu (naziv, ...) 3. Tabela Predaje - povezuje nastavnika sa predmetom 4. Popuniti tabele test podacima 2. Napisati JAVA program koji ce raditi sa navedenom bazom podataka pomoći Hibernate-a. Program treba da: 1. Uspostavi vezu sa konkretnom bazom podataka i mapirati potrebne objekte i tabele 2. Ima potrebne klase (za kreiranje objekata Nastavnik, Predmet, ...), kao i sve potrebne Hibernate objekte i konfiguracije
46
Poglavlje 5 Domaći zadatak 14
3. Ima metode za a. Unos, brisanje i izmene podataka nastavnika b. Unos, brisanje i izmene podataka predmeta c. Unos, brisanje i izmene podataka o angažovanju 4. Izvrši sledeće upite - HQL a. Kreirati 3 nova nastavnika i predmeta, b. Dodeliti novim nastavnicima po dva predmeta c. Prikazati sve nastavnike u bazi, uređene restuće po prvom slovu imena d. Prikazati sve nastavnike u bazi, uređene restuće po prvom slovu prezimena, koji imaju tri i više predmeta e. Prikazati predmete i nastavnike koji su na njima angažovani f. Prikazati predmete koje predaje nastavnik sa id = 1 g. Promeniti prezime nastavniku cije je ime Anica h. Obrisati nastavnike sa id = i + 3 (i = 0,1,2,...)
47
Zaključak ZAKLJUČAK Šta smo naučili u ovoj lekciji? U lekciji se na osnovu nekoliko primera može savladati korišćenje Hibernate za potrebe pisanja Java aplikacija nad relacionom bazom podataka. Hibernate je softver koji služi za objektno relaciono mapiranje kako bi se rešili pristupi u pisanju aplikacija (objektni pristup) i načinu čuvanja podataka u relacionim bazama podataka (relacioni a ne objektni pristup). .
48