JDBC | Jakarta/Java Enterprise Edition |
- Referenzimplementierung
- Verbindungsaufbau zur Datenbank
- Entity-Klassen aus einer Datenbanktabelle erzeugen
- Persistenzkonfiguration: persistence.xml
- Aktionen auf Entites: Der EntityManager
- Relationen
- JPA unter Jakarta/JEE
- Die Spalten einer Tabelle entsprechen den Attributen einer Klasse.
- Jedes Objekt steht für eine Zeile einer Tabelle.
JPA setzt auf dem JDBC-Treiber.
Referenzimplementierung
Die Referenzimplementierung für einen Persistence Provider, der JPA umsetzt, ist EclipseLink. EclipseLink ist Bestandteil des Application Servers Glassfish. Neben EclipseLink gibt es auch weitere Persistence Provider: Die JPA gehört nicht zum Standard-Umfang der Java Standard Edition oder Tomcat. In diesen Fällen muss die Bibliothek des Persistence Providers eingebunden werden. Diese JAR wird unter Eclipse bei Anlegen eines JPA-Projekts gleich angefordert und bei Bedarf automatisch heruntergeladen.Verbindungsaufbau zur Datenbank
Als Basis für die Beispiele dieser Seite wird PostgreSQL verwendet, dürfte aber auch mit den meisten anderen Datenbanken realisierbar sein. Das Szenario ist die Verwaltung einer Ferienwohnung. setzt diese Seite voraus.Zur Realisierung erstellen wir zunächst eine Standalone-Anwendungen mit JPA. Eclipse erzeugt es nach einem Aufruf von File|New|JPA Project. Es erscheint ein Dialog:
- Project name: Der Name des Projekts ist wichtig, weil er später der Default-Wert für die Persistence Unit wird.
- Target runtime: Hier wird das Java Development Kit (JDK) angegeben, unter dem das Projekt laufen soll. Der Einfachheit halber wird hier JDK-8 verwendet.
- JPA-Version: Hier wird die vorgegebene Version verwendet.
- Configuration: Hier wird Basic JPA Configuration vorgeschlagen.
Das ist vollkommen in Ordnung, muss also nicht über Modify
angepasst werden.
- Nun muss mit Next zur nächsten Seite gewechselt werden. Mit einem weiteren Next wird zur JPA Facet gewechselt.
- Plattform: Die aktuellste EclipseLink-Version auswählen.
- JPA-Implementation: Hier muss unter der User Library mindestens eine Bibliothek stehen. Ist dort keine, kann der Download-Button (Download Library) angeklickt werden. Dieser bietet einige Bibliotheken an. Davon wählen Sie die aktuellste.
- Nach dem erforderlichen Download erscheint die Bibliothek in der Liste.
- Unter Connection wählen Sie eine Datenbankverbindung.
Sofern Sie noch keine erstellt haben, klicken Sie auf Add connection
- Sie wählen zunächst an, mit welcher Datenbank gearbeitet werden soll. Wir wählen PostgreSQL aus.
- Nach Next wird der JDBC-Treiber angezeigt.
Es gibt in Folge eine Fehlermeldung, dass dieser (völlig veraltete)
Treiber nicht existiert. Er hilft dennoch weiter, weil man so unter
der Tab JAR List den Button Add JAR/Zip anwählen
kann und so einen aktuellen JDBC-Treiber installieren kann.
Einen aktuellen Treiber finden Sie unter der URL https://jdbc.postgresql.org/download.html.
Ist der in der Liste aufgeführt, kann der veraltete Eintrag geöscht werden.
- Nach Next finden Sie einen Dialog, in dem Sie die
Zugangsdaten zu Ihrer Datenbank angeben.
- Database: fewo
- URL: jdbc:postgresql://localhost:5432/fewo
- User name: fewoadmin
- Password: geheim
- Bei Save password einen Haken setzen
- Sie müssen den JDBC-Driver in den Projekt-Properties noch mit Add driver to build path anwählen.
- Mit Finish schließen Sie ab.
Entity-Klassen aus einer Datenbanktabelle erzeugen
Eclipse kann aus der erstellten Datenbank automatisch Entity-Klassen erstellen.Dazu klicken Sie das Projekt mit der rechten Maustaste an und wählen: New | JPA Entity from Table.
- Der Dialog zeigt die bei der Projekterstellung eingerichtete Datenbankverbindung unter Connection. Darunter können die Tabellen der Datenbank angewählt werden, für die Eclipse die passenden Entities erstellen soll.
- Unten ist eine Checkbox List generated classes in persistence.xml,
die einen Haken haben sollte.
- Next zeigt die Relationen zwischen buchung und gast sowie buchung und wohnung an.
- Hier sieht man, dass eine Buchung eine Referenz auf einen Gast und eine Wohnung hat.
- Umgekehrt referenziert ein Gast auf keine oder ganz viele Buchungen.
- Next ermöglicht die automatische Generierung der Schlüssel
beim Neuanlegen (INSERT/persist).
Unter Key generator lassen sich folgende Optionen einstellen.
- none: Die Verbindung wird manuell erstellt.
- auto
- identity: Funktioniert bei PostgreSQL, aber nicht bei Oracle
- sequence: Verwendet eine Sequence
- table: Verwendet eine Datenbanktabelle für die Schlüssel.
- Sie wählen identity und klicken aufFinish.
package model; import java.io.Serializable; @Entity @NamedQuery(name="Wohnung.findAll", query="SELECT w FROM Wohnung w") public class Wohnung implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; private String bez; private double preis; private Integer qm; //bi-directional many-to-one association to Buchung @OneToMany(mappedBy="wohnung") private Listbuchungs; // Es folgen ein leerer Standard-Konstruktor, Getter und Setter
Damit JPA die Klasse als Entity erkennt, wird sie mit der Annotation @Entity gekennzeichnet.
Für die Entity wird eine @NamedQuery definiert. Es handelt sich um eine SELECT-Anweisung, die später unter dem Namen Wohnung.findAll aufgerufen werden kann. Um flexible Anfragen zu ermöglichen, stellt JPA eine Reihe von SELECT-Anweisungen zur Verfügung.
Die Variable id wird mit @Id als Primärschlüssel gekennzeichnet. Ein solches Attribut muss zwingend vorhanden sein.Da beim Einfügen neuer Elemente von der Datenbank ein solcher Schlüssel erzeugt wird, muss mit der Annotation @GeneratedValue angegeben werden, wie dieser Schlüssel erstellt wird.
Die Attribute, die auf Spalten der Datenbanktabelle können mit @Column markiert werden. Dadurch ist es auch möglich, Spalten mit ungleichen Namen zu referenzieren. Tatsächlich werden alle Attribute automatisch als Referenzen auf Tabellenspalten aufgefasst, sofern sie nicht mit @Transient markiert werden.
Hinter @OneToMany wird eine 1:n-Beziehung zur Tabelle buchung durch eine Liste umgesetzt.
Annotationen
- @Entity: Die Klasse repräsentiert eine Tabelle. Es kann ein Name als Parameter verwendet werden, wenn die Datenbanktabelle anders heißt als die Klasse.
- @Column: Dieses Attribut steht für eine Spalte. Auch hier kann der Name der Spalte als Parameter festgelegt werden.
- @Transient: Dieses Attribut hat mit der Datenbank nichts zu tun.
- @Id: Diese Spalte ist ein Primärschlüssel
- @GeneratedValue: Die Spalte wird von der Datenbank bestückt.
Persistenzkonfiguration: persistence.xml
Die Datei persistence.xml definiert die Datenbankkonfiguration einer JPA-Anwendung. Bei Eclipse befindet sie sich im Projektordner JPA Content. Wird das Projekt allerdings durch einen Dateimanager oder per Terminal geöffnet, befindet sie sich unterhalb des Projektverzeichnis in src/META-INF.
- Die Datei definiert die Persistence Unit, die im Programm bei der Erstellung der EntityManagerFactory als Kennung für die Datenbank-Ressource aufgegriffen wird.
- Die untenstehende persistence.xml ist eine JTA-Variante, die man wählt, um die Konfiguration im Application Server durchzuführen. In unserem Beispiel muss sie auf Local Resource umgestellt werden.
- Die Datei pflegt auch die Entity-Klassen. Als Beispiel ist unten die Klasse Gast eingetragen.
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="gastPU" transaction-type="JTA"> <jta-data-source>jdbc/__meineDB</jta-data-source> <class>Gast</class> </persistence-unit> </persistence>Eclipse bietet neben der XML-Darstellung unter der Lasche Source einige Dialoge, die die Konfiguration vereinfachen.
- Unter dem Assistenten befinden sich verschiedene Laschen. Klicken Sie Connection an.
- Hinter Transaction type wählen Sie aus der Klappbox Resource Local aus.
- Der Link Populate from connection wird aktivierbar. Bitte anklicken.
- Driver, URL, User und Password werden gefüllt.
- [Strg]+[S] um die Änderungen zu speichern.
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="JpaStandalone" transaction-type="RESOURCE_LOCAL"> <class>model.Buchung</class> <class>model.Gast</class> <class>model.Wohnung</class> <class>model.Mietobjekt</class> <properties> <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/fewo"/> <property name="javax.persistence.jdbc.user" value="fewoadmin"/> <property name="javax.persistence.jdbc.password" value="geheim"/> <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/> </properties> </persistence-unit> </persistence>Anmerkung: Zur besseren Lesbarkeit wurden einige Zeilen umbrochen.
Aktionen auf Entites: Der EntityManager
Auslesen einer Tabelle
Das folgende Hauptprogramm soll eine Tabelle auslesen. Als einfache Tabelle wird die Wohnung herangezogen. Sie hat keine Referenzen, aber dafür Zahlen und Fließkommawerte.Für das Hauptprogramm wird das Package model rechts angeklickt und New|Class ausgewählt. Als Name der Klasse wird beispielsweise Main verwendet.
- Das folgende Programm erzeugt eine EntityManagerFactory.
- Dazu wird der Name der Persistence Unit aus der persistence.xml herangezogen, den der Assistent einfach aus dem Projektnamen übernimmt.
- Aus der Factory wird ein EntityManager erzeugt. Dieser ist für die Verwaltung der Entities zuständig. Er löst Anfragen und Befehle aus.
- In diesem Fall erzeugt der Manager über der Wohung eine Select-Query.
- Die Query übergibt ihr Ergebnis an eine Standard-Liste, die dann ausgewertet wird wie jede andere Liste.
package model; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.TypedQuery; public class Main { public static void main(String[] args) { EntityManagerFactory factory = null; factory = Persistence.createEntityManagerFactory("JpaStandalone"); // PU EntityManager manager = factory.createEntityManager(); TypedQuery<Wohnung> query = manager.createQuery ("select t from Wohnung t", Wohnung.class); List<Wohnung> liste = query.getResultList(); for (Wohnung wohnung : liste) { System.out.println(wohnung.getBez()); } } }
Der EntityManager
Der EntityManager sorgt dafür, dass die Daten zwischen Datenbanktabelle und den Java-Objekten hin und her gehen.Wenn Sie die Transaktionsverwaltung dem Application Server überlassen, dann erhalten Sie den EntityManager per Inject:
@PersistenceContext(unitName = "gastPU") private EntityManager entityManager;
In allen anderen Fällen, wie auch in unserem Beispiel, erzeugen Sie den EntityManager durch eine EntityManagerFactory. Die Factory wiederum erhält den Namen der Persistence Unit, die in der Datei persistence.xml beschrieben wird.
EntityManagerFactory factory = Persistence.createEntityManagerFactory("JpaStandalone"); EntityManager entityManager = factory.createEntityManager();
Suche über den Schlüssel
Wohnung wohnung = (Wohnung)manager.find(Wohnung.class, id);
Änderungen an den Wohnungen
Änderungen an Datenbanken erfolgen, wenn Sie ernst gemeint sind, als Transaktionen. Die Transaktion wird bei JPA durch den EntityManager eingeleitet und abgeschlossen.- manager.getTransaction().begin();
Die Transaktion wird eingeleitet. - manager.persist(entity);
Beliebig viele Aktionen auf der Datenbank - manager.getTransaction().commit();
Es hat alles geklappt, die Daten können übernommen werden. - manager.getTransaction().rollback();
Es war alles nur Spaß! Stelle den ursprünglichen Zustand der Datenbank wieder her.
Im folgenden Beispiel sollen alle Wohnungen auf die Standardgröße von 65 qm gebracht werden. Das wird dem Maurer schwerer fallen als dem Programmierer.
manager.getTransaction().begin(); for (Wohnung wohnung : liste) { wohnung.setQm(65); manager.persist(wohnung); } manager.getTransaction().commit();
Neuer Eintrag in der Datenbank
Ein neuer Eintrag in der Datenbanktabelle entsteht, wenn ein neues Entity-Objekt angelegt wird und über persist eingetragen wird.public static void insertNew(EntityManager manager) { Wohnung w = new Wohnung(); w.setBez("Parterre"); w.setQm(22); w.setPreis(450.0); manager.getTransaction().begin(); manager.persist(w); manager.getTransaction().commit(); }Im Falle der Wohnung wird die Datenbank eine ID erzeugen. Dazu muss der Eintrag für @GeneratedValue bei der Variablen id zur Datenbank passen.
Löschen der Wohnung
Ist die Wohnung erst einmal gefunden, kann sie mit remove gelöscht werden.Wohnung wohnung = (Wohnung)manager.find(Wohnung.class, id); manager.remove(wohnung);
Relationen
Bei einer 1:n-Beziehung steht eine Zeile einer Tabelle im Verhältnis zu mehreren Zeilen einer anderen Tabelle. So kann ein Kunde mehrere Bestellungen erhalten. In der Datenbank wird dies erreicht, indem die Tabelle Bestellung die ID des Kunden enthält.
Verbindung zwischen zwei Entities
Beim Auslesen einer Buchung wird automatisch der Gast und die Wohnung mit geladen, die mit der Buchung verknüpft sind. Falls es keinen Fremdschlüssel auf eine andere Tabelle gibt, liefert getWohnung bzw. getGast null zurück.EntityManager manager = getManager(); List<Buchung> buchlist = listBuchungen(manager); for (Buchung b : buchlist) { Wohnung w = b.getWohnung(); System.out.print("" + b.getId() + ": "+ b.getVon()); if (w!=null) { System.out.print(" " + w.getBez()); } System.out.println(); }
Foreign-Key in Entity
Eine Referenz der Entity Buchung auf eine andere Tabelle Gast (Foreign key), erfolgt über eine Collection-List (java.util) und @OneToMany.@OneToMany(mappedBy="gast") private ListDie referenzierte Klasse Gast muß nun ein Attribut mit dem Namen aufweisen, dass in OneToMany. Es muss vom Typ der referenzierenden Entity sein und wird mit @ManyToOne eingeleitet. @JoinColumn ist optional.buchungen;
@ManyToOne @JoinColumn(name = "gastid") private Gast gast;
JPA unter Jakarta/JEE
Ein vollwertiger Application Server enthält bereits einen JPA Persistence Provider. Die Datenbank kann dann durch den Administrator des Application Servers konfiguriert werden. Dieses Verfahren nennt sich JTA, da in diesem Fall der Application Server auch die Verwaltung der Transaktionen übernimmt.Eine JEE-Anwendung kann aber genau wie eine Java-SE-Anwendung die Konfiguration der JPA selbst übernehmen. Dies wird als Resource Local im Eclipse konfiguriert.
Erstellung eines Dynamischen Webprojekt mit JPA unter Eclipse
Nach der Einrichtung eines Dynamischen Webprojekts erscheint ein Dialog:- Project name: Der Name des Projekts ist relevant, da er später der Default-Wert für die Persistence Unit wird.
- Target runtime: Glassfish 5: enthält bereits die JPA-Libraries.
- Configuration: Hier den Button Modify anklicken. JPA anklicken OK.
- Die JPA-Konfiguration des Projekts erfolgt erst nach zweimal Next unter der Überschrift JPA Facet.
- Plattform: Die aktuellste EclipseLink-Version auswählen.
- JPA-Implementation: Hier muss unter der User Library mindestens eine Bibliothek stehen. Ist dort keine, kann der Download-Button (Download Library) angeklickt werden. Dieser bietet einige Bibliotheken an. Davon wählen Sie die aktuellste.
- Unter Connection wählen Sie eine Datenbankverbindung. Sofern Sie noch keine erstellt haben, klicken Sie auf Add connection
- Sie wählen zunächst an, mit welcher Datenbank gearbeitet werden soll. Wir wählen PostgreSQL aus.
- Nach Next wird der JDBC-Treiber angezeigt. Im Falle einer Fehlermeldung kann es sich um einen nicht existenten Treiber handeln. Ersetzen durch einen aktuellen, den Sie unter https://jdbc.postgresql.org/download.html herunterladen können.
- Nach Next finden Sie einen Dialog, in dem Sie die Zugangsdaten zu Ihrer Datenbank angeben.
- Database: fewo
- URL: jdbc:postgresql://localhost:5432/fewo
- User name: fewoadmin
- Password: geheim
- Bei Save password einen Haken setzen
- Mit Test Connection können Sie prüfen, ob Ihre Zugangsdaten stimmen. Dann können Sie den Dialog mit Finish beenden.
- Sie sollten den JDBC-Driver mit Add driver to build path anwählen.
- Mit Finish schließen Sie ab.
Konvertieren eines Projekts zu JPA
Auch ein Projekt, das bisher JPA noch nicht verwendet hat, kann darauf umgestellt werden:- Projekt mit rechter Maustaste anklicken.
- Configure...!Convert to JPA Project anwählen
- Klick auf Next. Die Seite JPA Facet wird sichtbar und kann wie oben beschrieben ausgefüllt werden.
- Finish
Links
Christian Dürr: Grundlagen der JPA
JEE-Literatur
Marcus Schießer, Martin Schmollinger:
Workshop Java EE 7
Etwas abstrakter: Dirk Weil: Java EE 7: Enterprise-Anwendungsentwicklung leicht gemacht
Das Buch enthält über 100 Seiten über JEE: Arnold Willemer: Java Alles-in-einem-Band für Dummies