8. Spring Data JPA OpenJpa
8.1. Einleitung
Wir greifen auf die vorherige Architektur zurück, die wir nun mit einer JPA-/OpenJpa-Schicht implementieren.
![]() |
8.2. Einrichtung der Arbeitsumgebung
Laden Sie mit STS das Projekt [myql-config-jpa-eclipselink] [1-4] herunter:
![]() |
und importieren Sie anschließend das Projekt [mysl-config-jpa-openjpa] [5], das sich im Ordner [<exemples>/spring-database-config/mysql/eclipse] [6] befindet:
![]() |
Anschließend setzen Sie die Maven-Umgebung (Alt-F5) aller in [Package Explorer] enthaltenen Projekte zurück:
![]() |
Führen Sie anschließend zur Überprüfung der Arbeitsumgebung die Ausführungskonfiguration mit dem Namen [spring-jpa-generic-JUnitTestDao-openjpa] aus:
![]() | ![]() |
Diese Konfiguration führt den Test [JUnitTestDao] aus. Dieser Test muss erfolgreich sein:
![]() |
8.3. Das Konfigurationsprojekt der Schicht JPA
![]() |
Dieses Projekt dient dazu, die Schicht JPA der folgenden Architektur zu konfigurieren:
![]() |
8.3.1. Maven-Konfiguration
Das Projekt ist ein Maven-Projekt und wird durch die folgende Datei [pom.xml] konfiguriert:
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>dvp.spring.database</groupId>
<artifactId>generic-config-jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>configuration mysql openjpa</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<!-- Variable Abhängigkeiten ********************************************** -->
<!-- JPA-Anbieter -->
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<version>2.3.0</version>
</dependency>
<!-- konstante Abhängigkeiten ********************************************** -->
<!-- Spring Data -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<!-- geerbte Konfiguration von JDBC -->
<dependency>
<groupId>dvp.spring.database</groupId>
<artifactId>generic-config-jdbc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
</project>
- Zeilen 5–7: Das von diesem Projekt generierte Maven-Artefakt. Es ist dasselbe wie das des Projekts [mysql-config-jpa-hibernate]. Das bedeutet, dass zu einem bestimmten Zeitpunkt nur eines dieser Projekte aktiv sein kann;
- Zeilen 10–14: das übergeordnete Maven-Projekt, das die Version der meisten für das Projekt erforderlichen Abhängigkeiten festlegt;
- Zeilen 19–23: die Bibliothek OpenJpa;
- Zeilen 26–29: die Spring-Data-Bibliothek;
- Zeilen 32–34: Das Konfigurationsprojekt der Schicht JPA basiert auf dem Konfigurationsprojekt der Schicht JDBC, das unter anderem den Treiber JDBC für das verwendete SGBD sowie die Koordinaten der zu verwendenden Datenbank definiert;
- Zeilen 35–40: Der Konfigurationsentwurf der Ebene JDBC enthält die Bibliothek [Spring JDBC], die hier durch die Bibliothek [Spring Data JPA] ersetzt wird. Daher wird empfohlen, sie nicht in die Projektabhängigkeiten aufzunehmen. Bleibt sie dennoch erhalten, verursacht dies jedoch keine Fehler;
Letztendlich lauten die Abhängigkeiten wie folgt:
![]() |
8.3.2. Spring-Konfiguration
![]() |
Die Klasse [ConfigJpa] konfiguriert das Spring-Projekt wie folgt:
package generic.jpa.config;
import generic.jdbc.config.ConfigJdbc;
import javax.persistence.EntityManagerFactory;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
@Import({ConfigJdbc.class})
public class ConfigJpa {
// der Provider JPA
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
OpenJpaVendorAdapter openJpaVendorAdapter = new OpenJpaVendorAdapter();
openJpaVendorAdapter.setShowSql(false);
openJpaVendorAdapter.setDatabase(Database.MYSQL);
openJpaVendorAdapter.setGenerateDdl(true);
return openJpaVendorAdapter;
}
// Entity-Pakete JPA
public final static String[] ENTITIES_PACKAGES = { "generic.jpa.entities.dbproduitscategories" };
// Datenquelle
@Bean
public DataSource dataSource() {
// Datenquelle TomcatJdbc
DataSource dataSource = new DataSource();
// Zugriffskonfiguration JDBC
dataSource.setDriverClassName(ConfigJdbc.DRIVER_CLASSNAME);
dataSource.setUsername(ConfigJdbc.USER_DBPRODUITSCATEGORIES);
dataSource.setPassword(ConfigJdbc.PASSWD_DBPRODUITSCATEGORIES);
dataSource.setUrl(ConfigJdbc.URL_DBPRODUITSCATEGORIES);
// anfänglich offene Verbindungen
dataSource.setInitialSize(5);
// Ergebnis
return dataSource;
}
// EntityManagerFactory
@Bean
public EntityManagerFactory entityManagerFactory(JpaVendorAdapter jpaVendorAdapter, DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(jpaVendorAdapter);
factory.setPackagesToScan(ENTITIES_PACKAGES);
factory.setDataSource(dataSource);
factory.afterPropertiesSet();
return factory.getObject();
}
// Transaktionsmanager
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
Diese Konfiguration entspricht der in Abschnitt 6.3.2 beschriebenen für die Hibernate-Implementierung JPA. Wir gehen hier nur auf die Unterschiede ein:
- Zeilen 23–30: Das Bean [jpaVendorAdapter] wird nun mit OpenJpa implementiert;
8.4. Die Datei [persistence.xml]
![]() |
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="generic-jpa-entities-dbproduitscategories" transaction-type="RESOURCE_LOCAL">
<!-- Entitäten JPA -->
<class>generic.jpa.entities.dbproduitscategories.Categorie</class>
<class>generic.jpa.entities.dbproduitscategories.Produit</class>
<class>generic.jpa.entities.dbproduitscategories.User</class>
<class>generic.jpa.entities.dbproduitscategories.Role</class>
<class>generic.jpa.entities.dbproduitscategories.UserRole</class>
<exclude-unlisted-classes />
</persistence-unit>
<persistence-unit name="generic-jpa-entities-dbproduits" transaction-type="RESOURCE_LOCAL">
<!-- Entitäten JPA -->
<class>generic.jpa.entities.dbproduits.Produit</class>
<exclude-unlisted-classes />
</persistence-unit>
</persistence>
- Zeile 4: Die mit der Datenbank verknüpfte Persistenzeinheit [dbproduitscategories]. Sie kann einen beliebigen Namen tragen (Attribut name);
- Zeilen 6–10: die fünf zu verwaltenden Entitäten JPA;
- Zeilen 13–17: eine weitere Persistenz-Einheit, die mit der Basis [dbproduits] verknüpft ist. OpenJpa ermöglicht eine Persistenzdatei mit mehreren Persistenz-Einheiten. EclipseLink lässt dies nicht zu. Zur Erinnerung: Bei Hibernate wurde keine Persistenzdatei verwendet;
8.5. Die Testschicht
![]() |
![]() |
Die oben genannten Tests sind identisch mit denen der Spring-Implementierungen JDBC, Spring JPA (Hibernate) und Spring JPA EclipseLink. Bei Bedarf siehe die folgenden Seiten:
- [JUnitTestCheckArguments]: Abschnitt 4.11.1;
- [JUnitTestDao]: Abschnitt 4.11.2;
- [JUnitTestPushTheLimits]: Abschnitt 4.11.3;
- [JUnitTestProxies]: Abschnitt 6.4.5;
Es sind folgende Ausführungskonfigurationen zu verwenden:
![]() | ![]() |
![]() | ![]() |
Damit die Entitäten JPA durch OpenJpa angereichert werden (woven), müssen die Java-Anwendungen oder die Tests JUnit mit einem Java-Agenten gestartet werden. Dieser erweitert die Entitäten JPA, bevor diese von JVM und [http://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/ref_guide_pc_enhance.html] geladen werden. Betrachten wir zum Beispiel die Konfiguration des Tests [JUnitTestDao]:
![]() |
- Auf der Registerkarte [Arguments] [1] wird die Referenz des Java-Agenten gemäß der Syntax [2] an JVM übergeben. Der Java-Agent ist das Archiv [openjpa-<version>.jar], das sich im Ordner [<m2-repo>/org/apache/openjpa/<version>] befindet. Der Ordner <m2-repo> ist in der Eclipse-Konfiguration angegeben ([3] siehe unten):
![]() |
In [2] (siehe oben) wurde eine benutzerdefinierte Variable [M2_REPO] verwendet:
![]() |
Der Variablen [M2_REPO] wurde der in [3] sichtbare Wert zugewiesen.
Die Ergebnisse der Tests mit den Variablen [JUnitTestDao] und [JUnitTestPushTheLimits] lauten wie folgt:
![]() |
![]() |
![]() |
- bei [1], [JUnitTestPushTheLimits-EclipseLink]: 70,583 s;
- in [2], [JUnitTestPushTheLimits-Hibernate]: 78,945 s;
- in [3], [JUnitTestPushTheLimits-JDBC]: 36,09 s;
- in [4], [JUnitTestPushTheLimits-OpenJpa]: 80,394 s;
Die für den Test [JUnitTestProxies] erzielten Konsolenergebnisse lauten wie folgt:
Hier ist zu sehen, dass beim Zugriff auf das Feld [Categorie.produits] einer Kategorie vom Typ PROXY und auf das Feld [Produit.categorie] eines Produkts vom Typ PROXY in beiden Fällen (Zeilen 7 und 17) ein Zeiger null vorliegt.























