Data Access API (DAO Pattern) - Beuth Hochschule für Technik Berlin

Сomentários

Transcrição

Data Access API (DAO Pattern) - Beuth Hochschule für Technik Berlin
Java Persistence API
(JPA)
© Christoph Knabe
Beuth-Hochschule Berlin
FB VI
12.06.2014
Gliederung
Geschichte Java Persistenz
 Mapping-Annotationen
 Assoziations-Annotationen
 Vererbungs-Annotationen
 Konfiguration
 Entity-Zustände
 Persistence bis EntityManager.persist
 Queries
 Fazit

Geschichte Java Persistenz

Java Database Connectivity (JDBC)

Erstmalig 1997 in JDK 1.1
http://docs.oracle.com/javase/7/docs/technotes/guides/jdbc

Vorbild war ODBC
Bietet Ausführung von Strings als SQL an.
— Großer Abstand Objekt ↔ Tabellenzeile

+ Alle Java-Persistenzframeworks basieren darauf.



Enterprise Java Beans (EJB) Entity Beans

1997 durch IBM, 1999 übernommen durch Sun

— schwergewichtig:
Entity muss bestimmte Interfaces implementieren.

— schwergewichtig: Läuft nur in EJB-Container.

— Deprecated ab EJB 3.1 (2009)
Geschichte II

Java Data Objects (JDO)

Erstmalig 2002 als JSR 12
http://db.apache.org/jdo/specifications.html

+ Plain Old Java Objects (POJO) persistierbar:
Es müssen keine Interfaces implementiert werden.
+ Gut in Speicherung von Objektgraphen
— Erfordert Byte-Code-Enhancing aller Entity-Klassen.



Java Persistence API (JPA)

Erstmalig 2006 als Teil von JSR 220 (EJB 3.0)
http://db.apache.org/jdo/specifications.html

+ Plain Old Java Objects (POJO) persistierbar:
Es müssen keine Interfaces implementiert werden.

Vorbilder waren Hibernate und TopLink.

+ Kommt ohne Byte-Code-Enhancing aus.
Mapping-Annotationen

@Entity vor Klasse: Persistierbar
@Table(name="tabellenname"): Wahl eines Tabellennamens
Attribut-Mapping durch Annotation
entweder vor Attributen oder Gettern
 @Id vor Primärschlüssel-Attribut

@GeneratedValue vor diesem: Wert wird durch JPA vergeben.

@Enumerated(EnumType.strategie) vor
enum-Attribut wählt
- Speicherung als String oder
- Speicherung als Ordnungszahl.

JSR-303 Bean Validation möglich, z.B.
- @NotEmpty: Weder null noch Länge 0
- @Size(min=..., max=...): Für Strings, Collections und Arrays
Assoziations-Annotationen

@Embedded vor Attribut
Referenziertes Objekt wird in derselben Tabellenzeile gespeichert.

@OneToOne vor Attribut
Referenziertes Objekt wird in eigener Tabelle gespeichert.

@ManyToOne vor Referenz-Attribut
Lädt referenziertes Objekt mit eigenem.
+ Ladeaufwand proportional Schreibaufwand: verständlich

@OneToMany vor Collection-Attribut
mit @JoinColumn(name = "fremdschlüssel"): Lädt in Collection
alle Zeilen, die mittels fremdschlüssel auf aktuelles Objekt zeigen.

Bidirektionale Verzeigerungen möglich
- Risiko, zu viel zu laden (z.B. bei m:n-Assoziation)
- Gegenrichtung muss in Java redundant gepflegt werden.
Besser: unidirektional (@ManyToOne) mit Suche bei Bedarf.
Vererbungs-Annotationen

@Inheritance vor Basisklasse
SINGLE_TABLE-Strategie: Objekte der Basisklasse und aller
Unterklassen werden in einer Tabelle gespeichert ⇒
Diskriminator-Spalte nötig. Konfigurierbar per
@DiscriminatorColumn, @DiscriminatorValue
— Platzverschwendung durch unbelegte Zellen

@Inheritance(strategy=InheritanceType.JOINED)
Jede Klasse (Basis, Unter) wird in eigener Tabelle gespeichert.
Zusammenführung über gemeinsamen Primärschlüssel.
+ Änderung einer Klasse ändert nur eigene Tabelle
— Objekt laden aufwändig wegen Join.

@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
Eine Tabelle je konkrete Klasse.
— Polymorphe Query aufwändig durch Union
— Polymorphe Assoziation zur Basisklasse unmöglich!
Beispiele:
https://www.assembla.com/code/lehrkraftnews/git/nodes/master/fb6/java/fb6/_any/db/DbObject.java
https://www.assembla.com/code/lehrkraftnews/git/nodes/master/fb6/java/fb6/lehrkraftnews/db
Konfiguration

JPA-Provider als Maven-Dependency
angeben
Bsp.:
https://www.assembla.com/code/lehrkraftnews/git/nodes/master/fb6/pom.xml

JPA konfigurieren
In META-INF/persistence.xml angeben:
Provider-Klasse, zu persistierende Klassen/Pakete,
Properties für JDBC-Verbindung, DB-Dialekt, SQL-Generierung,
Schema-Update
Bsp.:
https://www.assembla.com/code/lehrkraftnews/git/nodes/master/fb6/java/META-INF/persistence.xml
Entity-Zustände

Transient: vorübergehend
Nachdem Objekt mit new erzeugt wurde. Hat noch keine ID.
Nicht in Datenbank.

Persistent: dauerhaft
Wird erreicht durch Übergabe an EntityManager.persist.
Nur innerhalb einer Transaktion möglich. Änderungen werden bei
commit in die Datenbank gespeichert.

Detached: losgelöst
Nach einer Transaktion. Objekt hat noch seine ID, zu der es
wahrscheinlich noch eine Zeile in der DB gibt.
Ein Detached-Objekt kann durch EntityManager.merge wieder mit
der Datenbank verbunden (Persistent) werden.

Removed: gelöscht
Durch EntityManager.remove
Von Persistence zu persist

EntityManagerFactory erzeugen (teuer):
final EntityManagerFactory emf =
Persistence.createEntityManagerFactory("persistenceUnitName");

EntityManager erzeugen (billig):
final EntityManager em = emf.createEntityManager();

Transaktion beginnen:
em.getTransaction().begin();

Objekt erstellen und unter JPA-Verwaltung stellen:
final Person person = new Person("Müller", "Manfred");
em.persist(person);

Transaktion beenden:
em.getTransaction().commit();
bzw.
em.getTransaction().rollback();
Queries

JPQL-Queries (polymorph)
- Sollte generisch verpackt werden!
final Query query = em.createQuery("SELECT p FROM person
WHERE name = :name");
query.setParameter("name", "Müller");
final List<Object> personen = query.getResultList();

JPA 2 Criteria API Queries (typsicher)
final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<Person> cq = cb.createQuery(Person.class);
final Root<Person> rp = cq.from(Person.class);
final ParameterExpression<String> p
= cb.parameter(String.class);
cq.select(rp).where(cb.eq(rp.get("name", p));
final TypedQuery<Person> pq = em.ceateQuery(cq);
pq.setParameter(p, "Müller");
final List<Person> personen = pq.getResultList();
Fazit




+ Standard: Standardisiertes API für
Speicherung von Objekten in Relationalen DBen
+ Erfahrung: Basiert auf umfangreichen
Erfahrungen (positiv: Hibernate, negativ: EJBCMP)
+ Austauschbarkeit: Wegen Aufsetzen auf dem
Standard JDBC kann sowohl der
PersistenceProvider als auch das DBMS
ausgetauscht werden.
Mehr: Ausführliche Folien unter
http://www.kunkelgmbh.de/jpa/internal/JPA_mit_Hibernate.pdf