190 likes | 312 Views
Working With Persistent Objects. Persistente Domänenmodelle mit JPA 2.0 und Bean Validation. Persistence Context. Der Persistence Context definiert das physische Umfeld von Entities zur Laufzeit: die Menge aller Managed Entities in der Applikation den Entity Manager für diese Entities
E N D
Working With Persistent Objects Persistente Domänenmodelle mit JPA 2.0 und Bean Validation
Persistence Context • Der Persistence Context definiert das physische Umfeld von Entities zur Laufzeit: • die Menge aller Managed Entities in der Applikation • den Entity Manager für diese Entities • die laufende Transaktion • den Contexttyp
Kontext Typen • TRANSACTION • Standard im Java EE Umfeld • Lesender und schreibender Zugriff nur innerhalb der Transaktion. • Gelesene Objekte sind nach der Transaktion im Zustand detached • Wiedereinkopplung in eine Transaktion mit merge() • EXTENDED • Standard im Java SE Umfeld • Alle Objekte sind lesend und schreibend zugreifbar • Modifikationen finden lokal statt • Effekt von persist(), remove() usw. wird aufbewahrt • Propagation von Efffekten und Änderungen in die DB aber nur, wenn nachträglich begin()/commit() ausgeführt wird
Objektverwaltung • Der Transfer von Objekten von und zur Datenbank erfolgt automatisch: so spät wie möglich Lazy Access • Der Transfer von Objekten von und zur Datenbank kann manuell erzwungen werden synchron zum Aufruf • Selbstverständlich gilt ein Transaktionsmodell: Der Zugriff auf Objekte erfolgt ab Beginn der Transaktion, die Synchronisation mit der Datenbank wird spätestens beim Commit abgeschlossen und unterliegt der ACID-Regel • Auf Objekte kann auch ausserhalb von Transaktionen zugegriffen werden, jedoch ohne Konsistenz- und Synchronisationsgarantie
Objektzustand Objekte haben vier mögliche Zustände: • New • Objekt ist neu erzeugt, hat noch keinen Zusammenhang mit der Datenbank und noch keine gültige ID. • Managed • Das Objekt hat eine Entsprechung in der Datenbank. Änderungen werden vom Entity Manager automatisch getracked und mit der DB abgeglichen. • Detached • Das Objekt hat eine Entsprechung in der Datenbank, wurde aber abgekoppelt. Der Zustand wird nicht mehr automatisch abgeglichen mit der Datenbank. • Removed • Das Objekt existiert noch, ist aber zum Löschen markiert.
Entity persistieren • Mit persist() wird eine neue Entity vom EntityManager verwaltet • Die Methode contains() kann geprüft werden ob eine Entitymanaged ist Department dept = em.find(Department.class, deptId);Employee emp = new Employee();emp.setId(empId);emp.setName(empName);emp.setDepartment(dept);dept.getEmployees().add(emp);em.persist(emp);
Objekt ID • Ein neues Objekt bekommt erst eine ID, wenn es das erste Mal physisch in die Datenbank transportiert wird Employee emp = new Employee();em.persist(emp);System.out.println(emp.getId()); // null em.flush(); oderem.getTransaction().commit(); System.out.println(emp.getId()); // gültigeID, z.B. 1
Kaskadierte Persistenz (1) • Kaskadierte Persistenz heisst: Alle von einem persistenten Objekt aus erreichbaren Objekte sind ebenfalls persistent • Die Kaskadierung muss deklariert werden: • PERSIST • MERGE • REMOVE • REFRESH • ALL Employee employee = new Employee();em.persist(emp);Address address = new Address();employee.setAddress(address);
Kaskadierte Persistenz (2) • Die Kaskadierung kann für das Erstellen und das Löschen der Persistenz separat eingestellt werden • Die Kaskadierung bezieht sich nun auf die persist() und die remove()-Methode. public class Employee { @OneToOne( cascade={CascadeType.PERSIST, CascadeType.REMOVE } ) private Address address; ... }
OrphanRemoval (JPA 2.0) • Sollen abhängige Kindelemente bei to-many Beziehungen ebenfalls gelöscht werden, kann dies seit JPA 2.0 ebenfalls deklariert werden: @OneToMany(cascade=ALL, mappedBy=”customer”, orphanRemoval=true) private Set<Order> orders;
Entity suchen • Mit find() kann eine Entity über ihren Primary Key gefunden werden • Die gefunden Entity wird kommt automatisch in den Zustand managed • Da find() über den Primary Key sucht, kann diese Methode vom Persistence Provider optimiert werden und unter Umständen einen Datenbankzugriff vermieden werden • Soll eine one-to-one oder many-to-one Reference auf eine bestehende Entity gebildet werden, kann getReference() verwendet werden um das vollständige Laden der Target-Entity zu verhindern
Einlesen • Der Objektzustand wird beim ersten Zugriff auf das Objekt eingelesen. • Wenn FetchType.EAGER gesetzt ist, werden referenzierte Objekte ebenfalls mitgeladen. • Wenn FetchType.LAZY gesetzt ist, werden referenzierte Objekte beim ersten Gebrauch eingelesen. • Der Objektzustand wird nie automatisch aufgefrischt, nur via die EntityManager.refresh()-Methode. • Eine neue Transaktion führt nicht automatisch zum erneuten Einlesen bestehender Objekte.
Entity löschen • Mit remove() wird dem EntityManager mitgeteilt, dass diese Entity gelöscht werden kann Employee emp = em.find(Employee.class, empId);em.remove(emp);
Objektzustand nach Commit • Wenn der Persistence Context EXTENDED ist, bleibt ein Objekt im Zustand managed nach dem Commit. • Änderungen nach dem Commit werden aufbewahrt und im Rahmen der nächsten Transaktion in die Datenbank übernommen. • Wenn der Persistence Context TRANSACTION ist, geht ein Objekt in den Zustand detached über nach dem Commit. • Änderungen müssen mit EntityManager.merge() innerhalb der nächsten Transaktion wieder eingekoppelt werden.
Objektzustand nach Rollback • Nach einem Rollback ist jedes noch vorhandene Objekt im Zustand detached. Die Belegung der Felder wird durch den Rollback nicht geändert, jedoch der Zustand in der Datenbank • Vorsicht vor möglichen Inkonsistenzen • Objekte via Methoden des Entity Manager neu laden:find(), getReference(), createQuery() usw.
Persistence Context aufräumen • Ab und zu kann es vorkommen, dass der Persistence Context gelöscht werden soll • Dies kann mit der Methode clear() des EntityManager erreicht werden • Alle Entities kommen in den Zustand detached • Vorsicht: enthält der Persistence Context Änderungen welche noch nicht mit commit() gespeichert wurden, gehen diese verloren
Synchronisation mit der Datenbank • Das Zurückschreiben findet zum Commit-Zeitpunkt oder explizit mit der flush() Methode statt. • Das Zurückschreiben beinhaltet kein Refresh allfälliger Änderungen in der Datenbank in der Zwischenzeit -> Lost Update! • Das Zurückschreiben betrifft nur Änderungen, nicht ungeänderte Daten. Applikation m.setContent("A") tx.commit() m.setContent("C") tx.commit() SQL-Client update Message set content = 'B'; commit Zustand von m in Appl in DB A A A B C C
Foreign Key Constraints • Änderungsoperationen erzeugen oft Konflikte mit Fremdschlüssel-bedingungen, wenn Datensätze in der falschen Reihenfolge gelöscht werden. • Oracle erlaubt die Constraints DEFERABLE zu definieren, damit diese erst zum Commit Zeitpunkt geprüft werden: ALTER TABLE EMPLOYEE ADD CONSTRAINT EMPLOYEE_ADDRESS_FK FOREIGN KEY (ADDRESS_ID) REFERENCES ADDRESS(ID) DEFERRABLE INITIALLY DEFERRED;