Ich nehme derzeit an einer Akademie zum Java Fullstack Software Engineer teil. In den kommenden Wochen möchte ich hier meine Mitschrift, so gut es geht, aufzeichnen und mitteilen. Hier ist das, was ich vom ersten Tag in Block 6 gelernt und behalten habe:
DAO - Data Access Objekte
DAO ist eine Kopplung der Applikation via IO in Richtung Persistenz-Schicht.
Persistenz: Dauerhafte Datenspeicherung
- Datei (Text, csv, xml, json)
- Datenbanken
- Lochkarte
- Magnetstreifen, Chipkarten
- …
Kopplung (CRUD - Create, Read, Update, Delete)

JPA - Java Persistenz API
In gelb: Eigenschaften der Datenklassen. Diese sollen als Datensatz (z.B. Zeile in einer Tabelle) abgebildet werden.
In dem Moment, wo ich einer Datenklasse die Annotation @Entity angebe, schlägt der Classloader zu. Dieses Objekt soll dann via O/R (Objekt - Relation) Mapping gespeichert werden.
Um Namenskonflikte zu vermeiden, kann man die Annotation in Klammern setzen. (z.B. @Table(Mitarbeiter))
@ID geht auf Feld-Ebene. Er weiß automatisch, dass damit der Primary Key in der Tabelle gemeint ist.
Die Persistence.xml macht nicht nur das Mapping, sondern beinhaltet auch den Treiber, die URL, den User und das Passwort. Auch die CRUD-Optionen liegen dort drin (Achtung: Drop & Create zerstören die existierende Datenbank!):

Exkurs --> Unterschied zwischen SQL und NoSQL Datenbanken:

Die Windos Regestry ist eine hierarchische Datenbank (also non-Sql)
<-- Ende Exkurs
Im Java Community Process werden die Spezifikationen zukünftiger Versionen festgelegt:

Die Ergebnisse (also die JPA und JPA-Provider) findet man im MVN-Repository:

JPA Provider:
Sie sind eine Schicht innerhalb des JPA. Sie beinhalten oftmals spezifische Anforderungen:

Alle Anbieter bieten das Grundpaket, aber kochen auch ihr eigenes Süppchen.
JPA Übersicht (Siehe auch @Controler, @Service … von gestern):

Wir öffnen das von der Schulung mitgelieferte Package kap0310-jpa-app. Das Erste was man immer macht, wenn man ein "älteres" Package öffnet, ist die pom.xml anzupassen. Dazu checken wir auf der mvn-Repository-Seite die Versionen und tragen die neueste in die pom.xml ein. Außerdem checken wir, ob alles da ist:
- JPA-API (JSR 338 JPA 2.2)
- JPA-Provider (Hibernate, EclipseLink, TopLink, Spring Data, oder …)
DB-Treiber (Derby, HSQL, H2, MySQL, MariaDB, PostgreSQL, oder …)


- pom.xml <!-- API - Annotation --> <dependency> <groupId>org.hibernate.javax.persistence</groupId> <artifactId>hibernate-jpa-2.1-api</artifactId> <version>1.0.2.Final</version> </dependency><!-- Provider --> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.7.4</version> </dependency> <!-- DB -Treiber --> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>2.6.0</version> </dependency>
Datenklasse:
- Annotation
- @Entity // -> Für die JPA Teilnahme registrieren
- @Table // -> Bindung an den Tabellennamen im DBMS
- @Id // -> Eigenschaft welches den Primärschlüssel abbildet
- Konfiguration:
- resouces/META-INF/persistents.xml
In der Datenklasse Employee steht, wenn keine Annotationen drin wäre, ganz normaler "POJO" Java-Code.
Durch die Annotationen wird der Code aber "kontaminiert". Deswegen ist es Pflicht, dass die Api und der Provider in der pom.xml mitgeladen werden.
Die Annotations beziehen sich immer auf das nachfolgende Objekt.
@GeneratedValue(strategy = GenerationType.Auto) bedeutet, dass der Key im SQL-Server ein Autoincremented Key ist.

persistence.xml

Einbinden der Persistence-Unit (es können mehrere existieren):

Einbinden des Providers:

Einbinden der Annotation-Klasse:

Aktivierung der CRUD-Optionen:
<property name="javax.persistence.schema-generation.database.action" value="create" />
(Nochmal Achtung mit dem Drop. ):

Auch wenn der Wert "create" in der JPA benutzt wird, kann er durch den Provider überschrieben werden:

Zusammenfassung der persistence.xml:

Entity Object Life Cycle
CreateEmployee.java:

Suche die Klasse Employee und gebe mir das Objekt und dessen Eigenschaften, wo der Schlüssel 1201 ist. Der Provider/die JPA erstellt dann automatisch das SQL-Statement:

Rot: ausserhalb JPA
Blau: innerhalb JPA

Das bedeutet, dass ein flush, ein update und ein Delete durchgeführt wird, obwohl das Objekt schon übergeben wurde. Es wurde ja auch nur die Referenz auf das Objekt übergeben, daher kann man im Nachgang auch noch die Daten ändern. Erst mit dem Commit wird wirklich geschrieben:

Ein Update ist dementsprechend trivial:

Remove des Objektes in der Tabelle:

ORM - Object Relational Mapping

Entweder wir mappen über Annotations und kontaminieren damit den Java Code, oder wir erstellen eine xml-Datei, in dem die Objekte gemappt werden:

(Entnommen aus jpa_tutorial.pdf)
Die Annotation @Transient verhindert, dass Objekte in die Datenbank übertragen werden:

Übung ueb01-person-jpa
- Erzeugen Sie die Klasse Person
- Erweitern Sie die Klasse Person so das sie für die Java Persistenz-API zur Speicherung von Personen verwendet werden kann
- Richten Sie JPA mit den EclipceLink Provider so ein das wir Daten in einer HSQLDB verwalten können
- Erzeugen Sie 3-4 Personen Instanzen die Sie in der HSQLDB speichern.
- Lesen Sie Personendaten wieder aus der HSQLDB aus
- Ändern Sie an in der Datenbank bestehenden Personen Daten und persistieren Sie diese Personen erneut.
- Löschen Sie Personen aus der HSQLDB
Person.class
public class Person {
//Eigenschaften
private String vorname;
private String nachname;
private int alter;
private int puls;
…
}
Funktionierendes Ergebnis:
pom.xml:
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion><groupId>de.telekom</groupId>
<artifactId>ueb01-person-jpa</artifactId>
<version>1.0-SNAPSHOT</version><name>ueb01-person-jpa</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url><properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties><dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- API - Annotation -->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.2.Final</version>
</dependency><!-- Provider --> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.7.4</version> </dependency> <!-- DB-Treiber --> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>2.6.1</version> </dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
persistance.xml:
<?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="Eclipselink_JPA" transaction-type="RESOURCE_LOCAL"> <!-- <jta-data-source>java:jboss/datasources/MySqlDS</jta-data-source> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <provider>org.hibernate.ejb.HibernatePersistence</provider> <property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />--> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>de.telekom.jpa.Person</class> <properties> <!-- <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpadb?serverTimezone=Europe/Amsterdam&useSSL=false"></property> <property name="javax.persistence.jdbc.user" value="root" /> <property name="javax.persistence.jdbc.password" value="p@ssw0rd" /> <property name="javax.persistence.schema-generation.database.action" value="create" /> <property name="eclipselink.logging.level" value="FINE" /> --> <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbc.JDBCDriver" /> <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:file:jpadb"></property> <property name="javax.persistence.jdbc.user" value="SA" /> <property name="javax.persistence.jdbc.password" value="" /> <property name="javax.persistence.schema-generation.database.action" value="create" /> <property name="eclipselink.logging.level" value="FINE" /> <!-- <property name="eclipselink.ddl-generation" value="drop-and-create-tables" /> --> </properties> </persistence-unit>
</persistence>
CreatePerson.java:
package de.telekom.app;import de.telekom.jpa.Person;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;public class CreatePerson {
public static void main( String[ ] args ) {EntityManagerFactory emfactory = Persistence.createEntityManagerFactory("Eclipselink_JPA"); EntityManager entitymanager = emfactory.createEntityManager(); entitymanager.getTransaction().begin(); Person person = new Person(4711, "Achim", "Mertens", 52, 60); Person person2 = new Person(4712, "Amadeus", "Stephani", 55, 80); Person person3 = new Person(4713, "Michael", "Schneider", 12, 99); Person person4 = new Person(4714, "Matthias", "Schmitt", 23, 60); entitymanager.persist(person); entitymanager.persist(person2); entitymanager.persist(person3); entitymanager.persist(person4); entitymanager.getTransaction().commit(); entitymanager.close(); emfactory.close(); }
}
DeletePerson.java:
package de.telekom.app;import de.telekom.jpa.Person;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;public class DeletePerson {
public static void main( String[ ] args ) {
EntityManagerFactory emfactory = Persistence.createEntityManagerFactory("Eclipselink_JPA");
EntityManager entitymanager = emfactory.createEntityManager();
entitymanager.getTransaction().begin();
Person person = entitymanager.find(Person.class, (long)4711);
entitymanager.remove(person);
entitymanager.getTransaction().commit();
entitymanager.close( );
emfactory.close( );
}
}
FindAllPersonen.java:
package de.telekom.app;
import de.telekom.jpa.Person;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import java.util.List;
import java.util.Map;
public class FindAllPersonen {
public static void main( String[ ] args ) {
EntityManagerFactory emfactory = Persistence.createEntityManagerFactory("Eclipselink_JPA"); EntityManager entitymanager = emfactory.createEntityManager();Query query = entitymanager.createNamedQuery("find people"); List<Person> list = query.getResultList( ); for( Person p:list ) { System.out.print("Person ID :"+p.getId()); System.out.println("\t Personen-Name :"+p.getVorname( )); }
}
}
FindPerson.java
package de.telekom.app;import de.telekom.jpa.Person;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;public class FindPerson {
public static void main( String[ ] args ) {EntityManagerFactory emfactory = Persistence.createEntityManagerFactory("Eclipselink_JPA"); EntityManager entitymanager = emfactory.createEntityManager(); Person person = entitymanager.find(Person.class, (long)4711); System.out.println(person.toString()); }
}
UpdatePerson.java:
package de.telekom.app;import de.telekom.jpa.Person;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;public class UpdatePerson {
public static void main( String[ ] args ) {EntityManagerFactory emfactory = Persistence.createEntityManagerFactory("Eclipselink_JPA"); EntityManager entitymanager = emfactory.createEntityManager(); entitymanager.getTransaction().begin(); Person person = entitymanager.find(Person.class, (long)4711); System.out.println(person.toString()); person.setPuls(180); entitymanager.getTransaction().commit(); System.out.println(person.toString()); entitymanager.close(); emfactory.close(); }
}
Disclaimer
Alles was ich mitschrieb und verstanden habe ist ohne Gewähr.
Besten Dank an unseren sehr empfehlenswerten
Trainer: Hans-Joachim Blanke blanke@4point.de

In den nächsten Tagen und Wochen geht’s weiter, so: stay tuned!
Gruß, Achim Mertens