1. Tajti Ákos http://cesjava.freeblog.hu 2. az objektum-perzisztenciát biztosító eszközsegítségével adatbázistáblák helyett osztályokkal dolgozhatunka lekérdezésekben táblák helyett osztályneveket használhatunk, de ha nagyon muszáj, írhatunk SQL lekérdezéseket isA lényeg: A hibernate elrejti előlünk a fizikai adatbázist 3. Ha az osztályainkat le akarjuk képezni adatbázistáblákra, akkor meg kell adnunk egy ún.mappingfá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ípusanem primitív típus minden kollekció típusú adattagnál valamelyik kollekcióinterfésztadjuk meg típusnak (Map, List stb.) minden leképezni kívánt adattagnak (amit az adatbázistábla egyik oszlopakéntmeg akarunk jeleníteni) vangetter és settermetódusa 4. Az előző osztályhoz tartozó mapping állomány: f3t_seq 5. A mappingeket automatikusan generálhatjuk az adatbázis alapján. A későbbiant 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. 6. Amikor az adatbázisra leképezzük a projektünk osztályait, feldolgozásra kerülnek a mapping állományok:betöltődnek az egyes osztályok metaadatai, ellenőriznikell, hogy az adatbázis szerkezete megfelel-e az osztályok szerkezeténekstb.Ezután a mappingekből beolvasott adatok bekerülnek egySessionFactory példányba. ASessionFactorytehát tárolja az objektumok perzisztenssé tételéhez szükséges információkat. Mivel aSessionFactoryfelépítése nagyon időigényes, minden adatbázishozcsak egy példánytérdemes elkészíteni, amit minden osztály használ (singleton). A példában ezt a singletont aSessionFactoryFactoryosztály kezeli. ASessionFactorytartalmazhat másodlagos cache-t (paraméterrelállítható). 7. 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ételemindig egySession -ö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 objektumot sess.save(e) ; t.commit(); … 8. ASession JDBC kapcsolatokat csomagol be(azaz nem nekünk kell a kapcsolatot létrehozni, hanem mindenSession -höz jár egy). MindenSessionkötelezően tartalmazelsődleges cache-t . Azaz: ha az alkalmazás futása során egySession -ön belül lekérdeztünk már egy objektumot, akkor az amemó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 vanrá, mi nem is tudhatjuk, hogy mikor (kivéve ha kikényszerítjük aflushmetódussal (lásd később)). 9. Egyszálú, rövid életű objektum, amit arra használhatunk az alkalmazásban, hogy a munkaatomi lépéseitspecifikáljuk (azaz meghatározzuk, melyadatbá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ók kezelé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ítaniakarjuk az adatbázist, mindig el kell indítanunk egy új tranzakciót, és a végéncommitálnunk vagy visszagörgetnünk (persze nem úgy kell érteni, hogy mindeninsert, 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ó). 10. … 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álunk trans.commit(); … Ha a következő kódrészletből a vastag részek hiányoznának, kivételt kapnánk (csak akkor elnéző a hibernate, ha tranzakció-kezelőnek a beállításoknál aJDBCTransactionFactory-t adjuk meg (lásd később)); 11. Egy perzisztens osztály (ami le van képezve adatbázisra) három állapotbanlehet (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 egySession -ben élő objektum, amit már elmentettünk. Létezik elsődleges kulcsértéke és esetleg egy sor hozzá az adatbázisban. Ahibernate garantálja, hogy egySession -ön belül a perzisztencia id megegyezika Java id-vel, azaz használhatjuk az == operátort egyenlőségvizsgálatra. detached:az objektumot egyszer kapcsolatban volt egy Session-nel, de azt aSession-t már lezártuk, vagy egy másik folyamatban szerializáltuk a példányt. Tranziens Perzistens Detached új gc 12. //itt az objektum még tranziens, hiszen nem rendeltük hozzá/Sessiönhöz Example 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 10 Example e2 = (Example)sess.load(Example.class, 10); //ez most igazat ad vissza e == e2; trans.commit(); sess.close(); //lezárjuk a Sessiönt //az objektum itt márdetached . Ha a tranzakción belül kitöröltük//volna az adatbázisból,akkor most tranziens lenne. 13. A hibernate az objektum-perzisztenciát biztosító eszköz. Az objektumokleképezéséhez mapping állományokat használ. Amappingfájlok alapján felépül egySessionFactorypéldány, amiből minden adatbázishoz csakegyre van szükség. ASessionFactoryállítja elő nekünk azokat aSession objektumokat, amiken keresztül ténylegesen kommunikálhatunk az adatbázissal. ASessionbenolyan 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. A Sessiontovábbá futásidejű konzisztenciát biztosít, éselsődleges cache -t kínál a programozónak. Fontos interfész aTransactionis, ugyanis ezzel hordozhatóbbá válik azalkalmazásunk. 14. org.hibernate.SessionFactory openSession(): Elkészít egy adatbázis-kapcsolatot és létrehoz egy olyanSession -t, ami ezt a kapcsolatot csomagolja be. openSession(Connection conn): Létrehoz egy olyan Session-t, ami a paraméterként megkapottConnection példányt csomagolja be. Akkor lehet rá szükségünk, ha a JDBC és a hibernate API-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. 15. org.hibernate.Session beginTransaction(): Elindít egy munkaegységet, és visszaadja a hozzá tartozóTransactionpéldányt (azaz példányosítja aTransactionosztályt). close(): Lezárja a példányt és a hozzá tartozó JDBC kapcsolatot. createQuery(String hqlQuery): Elkészít egy futtathatóQuerypéldányt a paraméterül kapott HQL lekérdezésalapján. createSQLQuery(String sql): Elkészít egy futtatható SQLQuery példányt a paraméterül kapott SQLlekérdezés alapján. delete(Object o): Eltávolít egy perzisztens objektumot az adatbázisból. 16. org.hibernate.Session flush(): Flush-re kényszeríti aSession -t. Ilyenkor minden DML utasítás lefut, amit a hibernate optimalizációs okokból (hogy minél kevesebbszer kelljen a DB-t lekérdezés futtatására kérni) „visszatartott”. A metódus meghívása után biztosak 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 ( Objecttípussal) ha vanilyen, különben nullt. Aload -tól abban különbözik, hogy mindenképpen azadatbázishoz nyúl, míg aloadcsak ú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 aSessionbenbelül a megadottobjektumhoz tartozik. 17. org.hibernate.Session load(Class c, Serializable id): Betölti és visszaadja acosztályhoz tartozó táblából azt a sort, amiben azazonosító értékeid . Ha a konfigurációs fájlban meg nem változtatjuk ezt, akkor a hibernate alapesetben csak egy ún. proxyt tölt be. Azaz nem nyúl azadatbázishoz, hanem csak elkészít egyctípusú példányt, és annak azonosítóját beállítjaid -re. Ezzel sok fölösleges lekérdezés elkerülhető, például ha csak azért kell az objektum, hogy egy másik objektumban hivatkozzunk rá. Ezt nevezik „ lazy loading” -nak. refresh(Object o): Újra beolvassa azoobjektum állapotát az adatbázisból. save(Object o): Egy adatbázisbeli egyedi azonosítót rendel az objektumhoz (aminek a generálási módja a mapping állományokban van megadva), elmenti azt az adatbázisba, majd visszatér az azonosítóval ( Serializable ). 18. persist(Object o): Elmenti azoobjektumot 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ója megegyezik a megadott tranziens objektum,o ,Session -beli azonosítójával. saveOrUpdate(Object o): save(o)vagyupdate(o) , attól függően, hogy az objektumot korábbanperzisztenssé tettük-e már, vagy még nem. delete(Object o): Eltávolítja a perzisztensoobjektumot az adatbázisból. 19. org.hibernate.Transaction commit(): Befejezi a munkaegységet, és a szülőSession -ön végrehajt egy flush hívást, kivéve, ha aFlushMode.NEVERflushmó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, amiket abeginhívásokkal (a példányon) indítanak el. 20. Minden olyan metódus, ami aTransactionpéldányok manipulálásával vagy DML műveletekkel valamilyen kapcsolatban van,HibernateExceptionkivételt dob. Emiatt minden olyan kódot, amiben a hibernate API-t használjuk, kivételkezelő blokkban kell elhelyezni, aminek acatchágában vissza kell görgetni a tranzakciót (mert nem sikerült), afinallyágban pedig mindig le kell zárni aSession -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 van try{//a tranzakció metóusai is dobhatnak trans.rollback(); }catch(HibernateException e){ } }finally{ if(sess != null)try{//a session metódusai is dobhatnak sess.close(); }catch(HibernateException e){ } } 21. Szituáció: A cégnek egy olyan alkalmazásra van szüksége, amivel nagyon fontosExampleobjektumokat 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! 22. Importáljuk a szükséges osztályokat: package tajti.ex; //a hibernate osztályai import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.HibernateException; //a saját osztályunk a SessionFactory előállításához import 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 } } 23. 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 van try{//a tranzakció metóusai is dobhatnak trans.rollback(); }catch(HibernateException e){ } }finally{ if(sess != null)try{//a session metódusai is dobjatnak sess.close(); }catch(HibernateException e){ } } 24. A logikát megvalósító kód: //a sessiont a sessionfaktory példányosítja sess = SessionFactoryFactory.buildSessionFactory() .openSession(); //a transaction a sess példányhoz van rendelve trans = sess.beginTransaction(); //elmentjük az example objektumot sess.save(example); //nagybetűssé alakítja az s adattagot example.setS(example.getS().toUpperCase()); //majd frissít sess.update(s); //majd töröl sess.delete(s); trans.commit(); 25. //új atomi munkaegységet kezdünk, mert az előző végetért trans.begin(); //és újra mentünk sess.save(example); //és újra kommitálunk trans.commit(); Az alkalmazás a követelményeknek megfelel 26. 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ó azelőzőben is: propertynév=valami -> valami a hibernate API-n keresztül Ezt most hagyjuk. 27. A legfontosabb propertyk: hibernate.connection.driver_class Az 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ént elté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-ekhez esetleg sajátot implementálnak. A hibernate doksiban megtalálhatók a lehetségesértékei. Pl.:org.hibernate.dialect.OracleDialect 28. hibernate.show_sql Ha értéketrue , akkor munden DML művelet esetén mutatja a használt SQL utasítást. hibernate.order_updates Ha értéketrue , akkor frissítéskor a sorokat elsődleges kulcs alapján rendezi. Ez csö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: 29. Amit láttatok, az a hibernatenek csak egy része – az alapok. Sok metódusnak sokkal több túlterhelése van, és van olyan, amit be sem mutattam. Ezekről, és a hibernate mélyebb működéséről awww.hibernate.orgoldalon olvashattokbővebben. Ott nem az API-t érdemes nézegetni, mert elég „ritkás”. Inkább a hibernate wikivel foglalkozzatok. Sok sikert!