29
Tajti Ákos http://cesjava.freeblog.hu

Hibernate tutorial

Embed Size (px)

DESCRIPTION

hibernate bevezető. bővebben itt: http://cesjava.freeblog.hu

Citation preview

Page 1: Hibernate tutorial

Tajti Ákoshttp://cesjava.freeblog.hu

Page 2: Hibernate tutorial

• az objektum-perzisztenciát biztosító eszköz

• segítségével adatbázistáblák helyett osztályokkal dolgozhatunk

• a lekérdezésekben táblák helyett osztályneveket használhatunk, de ha nagyon muszáj, írhatunk SQL lekérdezéseket is

A lényeg:

A hibernate elrejti előlünk a fizikai adatbázist

Page 3: Hibernate tutorial

Ha az osztályainkat le akarjuk képezni adatbázistáblákra, akkor meg kell adnunkegy ún. mapping fájlban, hogy az egyes osztályoknak milyen tábla feleltethető meg, az egyes tábláknak mik az elsődleges kulcsai stb. Példa:

package tajti.ex;

public class Example{…

protected Integer i;protected String s;…

}

A hibernate csak olyan osztályokat képes leképezni, amelyekben:• az adattagok típusa nem primitív típus• minden kollekció típusú adattagnál valamelyik kollekció interfészt adjuk meg típusnak (Map, List stb.)• minden leképezni kívánt adattagnak (amit az adatbázistábla egyik oszlopaként meg akarunk jeleníteni) van getter és setter metódusa

Page 4: Hibernate tutorial

Az előző osztályhoz tartozó mapping állomány:<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >

<hibernate-mapping> <class name= "tajti.ex.Example" table= "EXAMPLE">

<id name= "i" type="java.lang.Integer" column="ID"> <generator class="sequence"> <param name="sequence">f3t_seq</param> </generator> </id> <property name= " s" type= " string" column=„S" not-null="true" length="15" /></class></hibernate-mapping>

Page 5: Hibernate tutorial

A mappingeket automatikusan generálhatjuk az adatbázis alapján. A későbbi ant script alapján.

A projekt könyvtárában adjuk ki ezt a parancsot:

ant generate.hbm

Ekkor a model alkönyvtárban megtaláljuk majd a mappingeket.

A hibernate konfigurációs fájlját a következő utasítás állítja elő:

ant generate.cfg

Ezt mindig aktualizálni kell, ha új mappingeket készítünk vagy generálunk.

Page 6: Hibernate tutorial

Amikor az adatbázisra leképezzük a projektünk osztályait, feldolgozásra kerülneka mapping állományok: betöltődnek az egyes osztályok metaadatai, ellenőrizni kell, hogy az adatbázis szerkezete megfelel-e az osztályok szerkezetének stb. Ezután a mappingekből beolvasott adatok bekerülnek egy SessionFactory példányba.

A SessionFactory tehát tárolja az objektumok perzisztenssé tételéhezszükséges információkat.

Mivel a SessionFactory felépítése nagyon időigényes, minden adatbázishoz csak egy példányt érdemes elkészíteni, amit minden osztály használ (singleton).A példában ezt a singletont a SessionFactoryFactory osztály kezeli.

A SessionFactory tartalmazhat másodlagos cache-t (paraméterrel állítható).

Page 7: Hibernate tutorial

Egyszálú, rövidéletű objektum, ami egy párbeszédet reprezentál az alkalmazásés a perzisztens tárolóhely között. Azaz az objektumok perzisztenssé tétele mindig egy Session-ön belül történik, ugyanígy a kiolvasás is. Példa:

…Example e = new Example();e.setI(15);

//létrehozunk egy Sessiont (aminek a faktorija a SessionFactory)Session sess = SessionFactoryFactory.buildSessionFactory().openSession();

Transaction t = sess.beginTransaction();//Így menthetünk el egy leképezett objektumotsess.save(e);

t.commit();…

Page 8: Hibernate tutorial

A Session JDBC kapcsolatokat csomagol be (azaz nem nekünk kell a kapcsolatotlétrehozni, hanem minden Session-höz jár egy).

Minden Session kötelezően tartalmaz elsődleges cache-t. Azaz: ha az alkalmazásfutása során egy Session-ön belül lekérdeztünk már egy objektumot, akkor az a memóriában marad, és legközelebb onnan kapjuk meg (persze ez befolyásolhatólockolással).

Megjegyzés: a hibernate csak akkor nyúl az adatbázishoz, ha tényleg szükség van rá, mi nem is tudhatjuk, hogy mikor (kivéve ha kikényszerítjük a flush metódussal(lásd később)).

Page 9: Hibernate tutorial

Egyszálú, rövid életű objektum, amit arra használhatunk az alkalmazásban, hogya munka atomi lépéseit specifikáljuk (azaz meghatározzuk, mely adatbázis-műveleteknek kell egy megbonthatatlan egységként végrehajtódniuk).

Elrejti a programozó elől a használt JDBC, JTA vagy CORBA tranzakciókat.Azaz: nem kell ezeknek az API-knak az osztályait használnunk a tranzakciókkezeléséhez, mert a hibernate elintézi ezt nekünk, ha megmondjuk, hogy JDBC, JTA vagy CORBA tranzakciókat használjon.

Fontos: a tranzakció demarkáció mindig kötelező. Azaz: ahányszor módosítani akarjuk az adatbázist, mindig el kell indítanunk egy új tranzakciót, és a végén commitálnunk vagy visszagörgetnünk (persze nem úgy kell érteni, hogy minden insert, update és delete egy új tranzakcióba kerüljön; csak az elemi lépéseknek (amik több műveletből állhatnak) kell új tranzakció).

Page 10: Hibernate tutorial

…Transaction t = sess.beginTransaction() Example e = (Example)sess.load(19); e.setS(”test”);

//elmentjük e-t sess.save(Example.class, e);

//kitöröljük a e-t sess.delete(e);//kommitálunktrans.commit();

Ha a következő kódrészletből a vastag részek hiányoznának, kivételt kapnánk (csakakkor elnéző a hibernate, ha tranzakció-kezelőnek a beállításoknál a JDBCTransactionFactory-t adjuk meg (lásd később));

Page 11: Hibernate tutorial

Egy perzisztens osztály (ami le van képezve adatbázisra) három állapotban lehet (egyszerre persze csak egyben):

• tranziens: az objektumot még soha nem mentettük az adatbázisba, nincs elsődleges kulcsértéke.

• perzisztens: a példány egy Session-ben élő objektum, amit már elmentettünk. Létezik elsődleges kulcsértéke és esetleg egy sor hozzá az adatbázisban. A hibernate garantálja, hogy egy Session-ön belül a perzisztencia id megegyezik a Java id-vel, azaz használhatjuk az == operátort egyenlőségvizsgálatra.

• detached: az objektumot egyszer kapcsolatban volt egy Session-nel, de azt a Session-t már lezártuk, vagy egy másik folyamatban szerializáltuk a példányt.

Tranziens Perzistens Detached

új gc

Page 12: Hibernate tutorial

//itt az objektum még tranziens, hiszen nem rendeltük hozzá /SessiönhözExample e = new Example();e.setI(10);

Session sess = SessionFactoryFactory.buildSessionFactory().openSession();

Transaction trans = sess.beginTransaction();

//itt az objektum perziszetenssé válik (elmentjük)sess.save(e);

//betöltjük azt az objektumot, aminek az id-je 10Example e2 = (Example)sess.load(Example.class, 10);

//ez most igazat ad visszae == e2;

trans.commit();sess.close(); //lezárjuk a Sessiönt//az objektum itt már detached. Ha a tranzakción belül kitöröltük //volna az adatbázisból,akkor most tranziens lenne.

Page 13: Hibernate tutorial

A hibernate az objektum-perzisztenciát biztosító eszköz. Az objektumok leképezéséhez mapping állományokat használ. A mapping fájlok alapjánfelépül egy SessionFactory példány, amiből minden adatbázishoz csak egyre van szükség. A SessionFactory állítja elő nekünk azokat a Sessionobjektumokat, amiken keresztül ténylegesen kommunikálhatunk az adatbázissal.A Sessionben olyan típusú objektumokat menthetük/törölhetünk/frissíthetünk,amely típusokat a mappingek segítségével leképeztük az adatbázisra. ASession továbbá futásidejű konzisztenciát biztosít, és elsődleges cache-t kínála programozónak.Fontos interfész a Transaction is, ugyanis ezzel hordozhatóbbá válik az alkalmazásunk.

Page 14: Hibernate tutorial

org.hibernate.SessionFactory

openSession():Elkészít egy adatbázis-kapcsolatot és létrehoz egy olyan Session-t, amiezt a kapcsolatot csomagolja be.

openSession(Connection conn):Létrehoz egy olyan Session-t, ami a paraméterként megkapott Connectionpéldányt csomagolja be. Akkor lehet rá szükségünk, ha a JDBC és a hibernateAPI-t vegyesen akarjuk használni.

evict():kitöröl minden entitást a másodlagos cache-ből.

close():Megsemmisíti a példányt, és felszabadítja minden erőforrását.

Page 15: Hibernate tutorial

org.hibernate.Session

beginTransaction():Elindít egy munkaegységet, és visszaadja a hozzá tartozó Transaction példányt (azaz példányosítja a Transaction osztályt).

close():Lezárja a példányt és a hozzá tartozó JDBC kapcsolatot.

createQuery(String hqlQuery):Elkészít egy futtatható Query példányt a paraméterül kapott HQL lekérdezés alapján.

createSQLQuery(String sql):Elkészít egy futtatható SQLQuery példányt a paraméterül kapott SQL lekérdezés alapján.

delete(Object o):Eltávolít egy perzisztens objektumot az adatbázisból.

Page 16: Hibernate tutorial

org.hibernate.Session

flush():Flush-re kényszeríti a Session-t. Ilyenkor minden DML utasítás lefut, amita hibernate optimalizációs okokból (hogy minél kevesebbszer kelljen a DB-tlekérdezés futtatására kérni) „visszatartott”. A metódus meghívása utánbiztosak lehetünk benne, hogy nincs piszkos adatunk.

get(Class c, Serializable id):Visszaadja a megadott id-jű példányát a c osztálynak (Object típussal) ha van ilyen, különben nullt. A load-tól abban különbözik, hogy mindenképpen az adatbázishoz nyúl, míg a load csak ún. proxy osztályt készít el.

get(Class c, Serializable s, LockMode lm):Ugyanaz, mint az előző,csak a harmadik paraméter szerint lockol.

getIndentity(Object o):Visszaadja azt az id-t (Serializable), ami a Sessionben belül a megadott objektumhoz tartozik.

Page 17: Hibernate tutorial

org.hibernate.Session

load(Class c, Serializable id):Betölti és visszaadja a c osztályhoz tartozó táblából azt a sort, amiben az azonosító értéke id. Ha a konfigurációs fájlban meg nem változtatjuk ezt, akkora hibernate alapesetben csak egy ún. proxyt tölt be. Azaz nem nyúl az adatbázishoz, hanem csak elkészít egy c típusú példányt, és annak azonosítójátbeállítja id-re. Ezzel sok fölösleges lekérdezés elkerülhető, például ha csakazért kell az objektum, hogy egy másik objektumban hivatkozzunk rá. Ezt nevezik„lazy loading”-nak.

refresh(Object o):Újra beolvassa az o objektum állapotát az adatbázisból.

save(Object o):Egy adatbázisbeli egyedi azonosítót rendel az objektumhoz (aminek a generálásimódja a mapping állományokban van megadva), elmenti azt az adatbázisba, majdvisszatér az azonosítóval (Serializable).

Page 18: Hibernate tutorial

persist(Object o):Elmenti az o objektumot az adatbázisba, de nem adja vissza a hozzá rendelt id-t.

org.hibernate.Session

update(Object o):Frissíti azt a perzisztens objektumot (o állapotával), aminek az azonosítójamegegyezik a megadott tranziens objektum, o, Session-beli azonosítójával.saveOrUpdate(Object o):save(o) vagy update(o), attól függően, hogy az objektumot korábban perzisztenssé tettük-e már, vagy még nem.

delete(Object o):Eltávolítja a perzisztens o objektumot az adatbázisból.

Page 19: Hibernate tutorial

org.hibernate.Transaction

commit():Befejezi a munkaegységet, és a szülő Session-ön végrehajt egy flush hívást,kivéve, ha a FlushMode.NEVER flushmód be van állítva.

rollback():Visszagörgeti a tranzakciót.

wasCommitted(), wasRolledBack():Elmenti, hogy a tranzakciót kommitálták-e, illetve visszagörgették-e.begin():Új tranzakcióba kezd.

setTimeout(int secs):Beállítja, hogy legfeljebb hány másodpercig futhatnak azok a tranzakciók, amiketa begin hívásokkal (a példányon) indítanak el.

Page 20: Hibernate tutorial

Minden olyan metódus, ami a Transaction példányok manipulálásával vagy DMLműveletekkel valamilyen kapcsolatban van, HibernateException kivételt dob.Emiatt minden olyan kódot, amiben a hibernate API-t használjuk, kivételkezelőblokkban kell elhelyezni, aminek a catch ágában vissza kell görgetni a tranzakciót(mert nem sikerült), a finally ágban pedig mindig le kell zárni a Session-t:

Session sess = null;Transaction trans = null;try{

//a hibernate apit használó kód}catch(HibernateException ex){

if(trans != null) //ez maradhat null, ha gond vantry{ //a tranzakció metóusai is dobhatnak

trans.rollback();}catch(HibernateException e){ }

}finally{if(sess != null)

try{ //a session metódusai is dobhatnaksess.close();

}catch(HibernateException e){ }}

Page 21: Hibernate tutorial

Szituáció:A cégnek egy olyan alkalmazásra van szüksége, amivel nagyon fontos Example objektumokat tudunk perzisztenssé tenni. Egyelőre csak az látszik, hogy menteni kell tudni a példányokat, de mi előrelátóak vagyunk, és készítünk egy olyan alkalmazást, ami elemi műveletként elmenti, frissíti, törli az objektumokat, majd egy másik elemi műveletben újra elmenti azokat. Speciális követelmény, hogy az alkalmazásnak, ha nem sikerül a művelet, a következő szöveget kell a szabványos kimenetre írnia:

Muck, You Lose!

Page 22: Hibernate tutorial

Importáljuk a szükséges osztályokat:

package tajti.ex;

//a hibernate osztályaiimport org.hibernate.Session;import org.hibernate.Transaction;import org.hibernate.HibernateException;

//a saját osztályunk a SessionFactory előállításáhozimport faktum3t.appserv.server.logic.SessionFactoryFactory;

Ezután a szokásos dolgok jönnek:

public class ExampleApp{public static void saveIt(Example example){

//ide jön majd a kód}

}

Page 23: Hibernate tutorial

A kódba érdemes először beletennünk a szokásos kivételkezelő részt:

Session sess = null;Transaction trans = null;try{

//ide jön majd a logikát megvalósító kód}catch(HibernateException ex){System.out.println(„Muck, You Lose!”);

if(trans != null) //ez maradhat null, ha gond vantry{ //a tranzakció metóusai is dobhatnak

trans.rollback();}catch(HibernateException e){ }

}finally{if(sess != null)

try{ //a session metódusai is dobjatnaksess.close();

}catch(HibernateException e){ }}

Page 24: Hibernate tutorial

A logikát megvalósító kód:

//a sessiont a sessionfaktory példányosítjasess = SessionFactoryFactory.buildSessionFactory()

.openSession();

//a transaction a sess példányhoz van rendelvetrans = sess.beginTransaction();

//elmentjük az example objektumotsess.save(example);

//nagybetűssé alakítja az s adattagotexample.setS(example.getS().toUpperCase());

//majd frissítsess.update(s);

//majd törölsess.delete(s);

trans.commit();

Page 25: Hibernate tutorial

//új atomi munkaegységet kezdünk, mert az előző végetérttrans.begin();

//és újra mentünksess.save(example);

//és újra kommitálunktrans.commit();

Az alkalmazás a követelményeknek megfelel

Page 26: Hibernate tutorial

A hibernate konfigurációjához három helyen szólhatunk hozzá:

• hibernate.cfg.xml Ezt automatikusan generálható egy ant scripttel. Ebben a fájlban le van írva, hogy melyik osztályt melyik mapping állomány képezi le.

• hibernate.properties Minden beállítás, amit ebben az állományban adunk meg, megadható az előzőben is:

propertynév=valami -> <property name=”propertynév”>valami</property>

• a hibernate API-n keresztül Ezt most hagyjuk.

Page 27: Hibernate tutorial

A legfontosabb propertyk:

hibernate.connection.driver_classAz adatbázisunkhoz tartozó JDBC driver neve. Pl.: oracle.jdbc.OracleDriver

hibernate.connection.url A JDBC kapcsolat URL-je, amin keresztül a DB elérhető. Adatbázisgyártónkénteltérő. Pl.: jdbc:oracle:thin:@192.168.12.26:1521:faktum

hibernate.connection.username Az adatbázis használatához szükséges felhasználónév

hibernate.connection.password A felhasználó jelszava.

hibernate.dialect Az adatbázisunk dialektusa. Ez általában a hibernatehez jár, speciális DBMS-ekhezesetleg sajátot implementálnak. A hibernate doksiban megtalálhatók a lehetséges értékei. Pl.: org.hibernate.dialect.OracleDialect

Page 28: Hibernate tutorial

hibernate.show_sql Ha értéke true, akkor munden DML művelet esetén mutatja a használt SQLutasítást.

hibernate.order_updates Ha értéke true, akkor frissítéskor a sorokat elsődleges kulcs alapján rendezi. Ezcsökkentheti a tranzakciók holtpontjait a nagyon terhelt rendszerekben.

www.hibernate.org/hib_docs/v3/reference/en/html/session-configuration.html

További konfigurációs részletek itt:

Page 29: Hibernate tutorial

Amit láttatok, az a hibernatenek csak egy része – az alapok. Sok metódusnaksokkal több túlterhelése van, és van olyan, amit be sem mutattam. Ezekről, és ahibernate mélyebb működéséről a www.hibernate.org oldalon olvashattok bővebben. Ott nem az API-t érdemes nézegetni, mert elég „ritkás”. Inkább ahibernate wikivel foglalkozzatok.

Sok sikert!