3. Perzisztencia (2012)
A VIK Wikiből
Szerializálás
Serializable interfész
- csak az szerializálódik, ami meg van vele jelölve
- formális
- tömbök szerializálódnak
- Object, Thread, Socket, nem szerializálódnak
- transient és static cuccok nem szerializálódnak
- a private static final %ObjectStreamField[] serialPersistentFields tömbben megjelölt cuccok szerializálódnak
- Leszármazottak szerializálás-lánca megszakítható a read/writeObject-ben NotSerializableException dobásával
Kimentés
class SerializableClass implements java.io.Serializable try { FileOutputStream f = new FileOutputStream("filename"); ObjectOutputStream out = new ObjectOutputStream(f); out.writeObject(_SerializableClass); out.close(); } catch(IOException ex) { ... }
Visszaállítás
try { FileInputStream f = new FileInputStream("filename"); ObjectInputStream in = new ObjectInputStream(f); o_ins = (SerializableClass)in.readObject(); in.close(); } catch(IOException ex) { ... } catch(ClassNotFoundException ex) { ... }
ObjectOutput interfész
- mindenre throws IOException
- writeObject(Object obj)
- write(int b)
- write(byte b[])
- write(byte b[], int off, int len)
- flush()
- close()
- http://download.oracle.com/javase/1.4.2/docs/api/java/io/ObjectOutput.html
ObjectInput interfész
- throws ClassNotFoundException, IOException
- Object readObject()
- read...()
- public long skip(long n)
- public int available()
- public void close()
- http://download.oracle.com/javase/1.4.2/docs/api/java/io/ObjectInput.html
Externalizable interfész
- csak az osztály azonosítása mentődik automatikusan, a többi a mi kezünkben
- kiírás/beolvasás felüldefiniálása
- writeExternal(ObjectOutput out)
- readExternal(ObjectInput in)
Hibernate 3.0
Alkalmazás átalakítása
- ID attribútumok (jól jöhet)
- konfigurációs fájl (xml)
- HSQL DB indítás
Leképezés
- <hibernate-mapping> gyökérelem
- <class> perzisztens osztály -> tábla
- <id>, <generator> azonosító, generátor algoritmus (pl native)
- <property> attribútum -> oszlop
- <many-to-one>, <one-to-one>, reláció
<hibernate-mapping> <class name="auto.Person" table="PERSON"> <id name="id" column="PERSON_ID"> <generator class="native"/> </id> <property name="name"/> <set name="cars" inverse="true" cascade="persist"> <key column="PERSON_ID" not-null="true"/> <one-to-many class="auto.Car"/> </set> </class> <class name="auto.Car" table="CAR"> <id name="id" column="CAR_ID"> <generator class="native"/> </id> <property name="platenr"/> <many-to-one name="owner" class="auto.Person" column="PERSON_ID" not-null="true" cascade="persist"/> </class> </hibernate-mapping>
Kollekciók
- <set>, <list>, <map>, <bag>, <array>, <<p>-array>
- Javaban a megfelelő Collection interfészt kell használni, nem castolható
<class name="Product"> <id name="serialNumber" column="SN"/> <set name="parts"> <key column="SN" not-null="true"/> <one-to-many class="Part"/> </set> </class>
Asszociáció
- kapcsolótáblával (join table) vagy anélkül
- referencia más osztályokra
- lásd reláció (1:1, 1:n, n:1, n:m)
Öröklés
- Támogatott:
- table-per-class-hierarchy (minden egy táblában, discriminator: típusjelölő)
<class ...> <discriminator column="PAYMENT_TYPEâ\x{fffd}\x{fffd} type="string"/> <subclass name="CredCPay" discriminator-value="CREDIT"> <property name="credCType" column="CCTYPE"/> ... </subclass> </class>
- table-per-subclass
<class ...> <joined-subclass name="CredCPayment" table="CREDIT_PAYMENT"> <key column="PAYMENT_ID"/> <property name="credCType" column="CCTYPE"/> ... </joined-subclass> </class>
- table-per-concrete-class
<class ...> <union-subclass name="CredCPayment" table="CREDIT_PAYMENT"> <property name="credCType" column="CCTYPE"/> ... </union-subclass> </class>
Objektumok kezelése
- Állapotok (Session-höz képest):
- tranziens - még nem kapcsolódótt
- perzisztens - adatbázistáblával összekötve
- lekapcsolt (detached) - már nem kapcsolódik
- Műveletek:
- session.flush() - módosítások mentése
- session.update(x) - újrakapcsolódás DB-hez, mentés
- session.saveOrUpdate(x) - elmenti az objektumot. Ha az id property-je null, akkor SQL INSERT utasítást hajt végre, ha not null, akkor SQL UPDATE utasítást hajt végre
- session.merge(x) - DB-ben és memóriában lévő cuccok összefésülése
- session.delete(x) - törlés
Tranzakciók
- csak így érhető el a DB
- Session osztály
Lekérdezések
- Query q = session.createQuery(…);
- visszatérés: skalár vagy tömb
X x = (X)session.createQuery(..).uniqueResult(); List l = session.createQuery(..).list(); Iterator i = session.createQuery(..).iterate();
- paraméterek: név (:xname) vagy sorszám (? ? ?)
q.setString("x", "param"); q.setString(1, "param1");
HQL
- From
- Join (inner, left outer, right outer, full outer)
- Select
- Aggregáló funkciók (avg(), sum(), min(), max(), count())
- Where
- Order by, Group by
- Constrainteket is kezel
JPA (Java Persistance API)
Alapok
- entitások: POJO (Plain olda java object) - szerializálhatónak kell lennie (más nem is kell)
- szabványos O-R kapcsolat
- lekérdezhetöség
- Entity Manager (EM) a felügyelö
- Persistence context (PC): perzisztens objektumok futási környezete, élettartamár a konténer vagy az alkalmazás menedzseli
- Session (hibernate) == EM (JPA) ??
- Persistence Unit: standard könyvtárszerkezet, O-R leképezéseket, relációkat, ezek hatásközét tartalmazza, illetve Java annotációkat és/vagy XML-t (persistence.xml)
Entitás
- @Entity annotáció (vagy XML)
- public vagy protected argumentum nélküli konstruktora van (final kizárva: osztály, metódus, változó)
- Serializable-t implementálja
- örökölhet entitástól vagy POJO-tól, POJO örökölhet entitástól
- konténeren kívül is használhatóak
Perzisztens elemek
- mezötöl és propertytöl is függ hogy perzisztens-e
- nem szerializálható elemek: static, transient, @Transient
- szerializálhatóak: mezök és propertyk (@Basic): primitiv, string, wrapper, byte[], char[], enum, Collection, Set, List, Map (generic is), összetett, beágyazott (@Embedded)
- betöltés lehet: Eager és Lazy
Kulcs
- Primary key kötelezö
- egyszerü kulcs: @Id, ami lehet primitiv, wrapper, string, date
- összetett kulcs
- Primary Key osztály: @IdClass
- Kulcs elem: @EmbeddedId
- kulcsgenerálás: @GeneratedValue(strategy = GenerationType.X), ahol X = AUTO, SEQUENCE, IDENTITY, TABLE
Entitások életciklusa
- Entity Manager müveletei: persist, refresh, remove, merge
- Entity Manager egyéb müveletei: find, getReference, flush, clear, Query
- tranzitivitas: reláció paramétere, cascase = (müveletek) + ALL
@Entity public class MyClass implements Serializable { @Basic Date birthday; } <entity name="mydonain.MyClass"> <attributes> <basic name="birthday"/> </attributes> </entity>
Relációk
- megegyezik a Hibernate-tel
- Annotációs: @OneToOne, @OneToMany, @ManyToOne, @ManyToMany
- egy- és kétirányú, kétirányúnál tulajdonos oldal - idegen kulcs, inverz oldal - referencia (mappedBy = )
@Entity public class Car implements Serializable { @ManyToOne private Person owner; @Entity public class Person implements Serializable { @OneToMany(mappedBy = "owner") private Collection<Car> cars = new HastSet();
Öröklés
- table-per-class-hierarchy, table-per-subclass, table-per-concrete-class
Lekérdezések
- JPQL (Java Persistence Query Language)
- Statikus lekérdezések: @NamedQuery, @NamedNativeQuery
@Entity @NamedQuery(name = "carByplate", query = "SELECT c FROM Car c WHERE c.plate = :rsz") Car c = (Car) em.createNamedQuery("carBypalte").setParameter("rsz", plate).getSingleResult();
- Dinamikus lekérdezések: runtime string komponálás, paraméterezéssel
Query query = em.createQuery("SELECT p FROM Product p WHERE p.param2 < :threshold ORDER BY p.param1 ascending"); query.setParamater("threshold", my_threshold); List results = query.getResultList();
- Natív SQL lekérdés a konkrét DB nyelve szerint, számozott paraméterezéssel
Query query = em.createNativeQuery("SELECT * FROM Product p WHERE p.param2 < ?1"); query.setParameter(1, my_threshold).setMaxResults(10); List results = query.getResultList();
- Criteria Query (Hibernate), Builder minta szerint futás közben
CriteriaQuery cq1 = em.getCriteriaBuilder().createQuery(); cq1.select(cg1.from(Person.class)); Iterator iter = ((List<Person>) em.createQuery(cq1).getResultList()).iterator();
PSEPro (ObjectStore)
- OO adatbázis, 50 MB adatkezelés, egy-felhasználós, konkurens session-ök, alkalmazáson belül fut, nincs külsö adatbázis, szemétgyüjtés megoldva
Objektumok tulajdonságai
- Állapotok:
- hollow (üres) - egy üres objektum, amibe az adatbázisból késleltetetten betölthetőek az adatok
- aktív - adatbázisban kapcsolatban áll (clean/dirty)
- stale (lejárt) - adatbázishoz nem kapcsolt
Szálak és Sessionök
- egyidőben egy adatbázishoz kapcsolódhat
- tetszőleges read-only tranzakciója lehet
- egyetlen update tranzakciója lehet
- session public static Session create(String host, Properties props)
- session létrehozása és törlése
public static Session create(String host, Properties props) public boolean isActive() public void terminate()
- szálak kapcsolódása és lecsatolása
public void join() public static void leave()
Adatbázisok
- adatbázis létrehozás, megnyitás, bezárás
public static Database create(String name, int fileMod) public static Database open(String name, int openMode) public void close(boolean RetainAsTransient)
Tranzakciók
- egyszerre egy sessionhöz kapcsolódhat
- kiadhat read-lockot és update-lockot is
public static Transaction begin(int type) public void commit(int retain) public void abort(int retain)
Objektumok
- perzisztenciához az objektumok root-tá tesszük
db.createRoot("foo", new Integer(5)); int x = (int)db.getRoot("foo"); db.setRoot("foo", null); db.destroyRoot("foo");
- minden kollekciónak megvan a maga OS... megfelelője
Query
- paraméteres lekérdezés (fv opcionális)
FreeVariables fv = new FreeVariables(); fv.put("IS", Integer.TYPE); Query q = new Query(Person.class, "getSalary()>=IS", fv); Collection employees = (Collection)db.getRoot("employees"); FreeVariableBindings fvb = new FreeVariableBindings(); fvb.put("IS", new Integer(20000)); Set result1 = q.select(employees, fvb); // több eredmény Object result2 = q.pick(employees, fvb); // egyetlen eredmény
Példa
private String dbName = "cardb.odb"; private Session session; private Database db; private Set carOwners; public void initDB() { session = Session.create(null, null); session.join(); try { db = Database.open(dbName, ObjectStore.UPDATE); } catch (DatabaseNotFoundException e) { db = Database.create(dbName, ObjectStore.ALL_READ | ObjectStore.ALL_WRITE); } Transaction tr = Transaction.begin(ObjectStore.UPDATE); try { carOwners = (Set)db.getRoot("OwnersRoot"); } catch (DatabaseRootNotFoundException ex) { carOwners = new OSHashSet(); db.createRoot("OwnersRoot", carOwners); } tr.commit(ObjectStore.RETAIN_HOLLOW); }
-- MeszegetoBalazsIstvan - 2008.05.27.
-- Velias - 2009.05.26.
-- Vad Zsolt - 2011.04.07.