8. Spring Data JPA OpenJpa
8.1. Introduction
Wracamy do poprzedniej architektury, którą teraz wdrażamy z warstwą JPA / OpenJpa.
![]() |
8.2. Konfiguracja środowiska pracy
Za pomocą pliku STS pobierz projekt [myql-config-jpa-eclipselink] [1-4]:
![]() |
a następnie zaimportuj projekt [mysl-config-jpa-openjpa] [5] znajdujący się w folderze [<exemples>/spring-database-config/mysql/eclipse] [6]:
![]() |
Następnie zresetuj środowisko Maven (Alt-F5) dla wszystkich projektów znajdujących się w folderze [Package Explorer]:
![]() |
Następnie, aby sprawdzić środowisko robocze, uruchom konfigurację uruchomieniową o nazwie [spring-jpa-generic-JUnitTestDao-openjpa]:
![]() | ![]() |
Ta konfiguracja uruchamia test [JUnitTestDao]. Test ten musi zakończyć się powodzeniem:
![]() |
8.3. Projekt konfiguracji warstwy JPA
![]() |
Zadaniem tego projektu jest skonfigurowanie warstwy JPA w poniższej architekturze:
![]() |
8.3.1. Konfiguracja Maven
Projekt jest projektem Maven i jest skonfigurowany za pomocą następującego pliku [pom.xml]:
<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>
<!-- zmienne zależności ********************************************** -->
<!-- JPA dostawca -->
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<version>2.3.0</version>
</dependency>
<!-- stałe zależności ********************************************** -->
<!-- Spring Data -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<!-- konfiguracja odziedziczona po 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>
- wiersze 5–7: artefakt Maven wygenerowany przez ten projekt. Jest to ten sam artefakt, co w projekcie [mysql-config-jpa-hibernate]. Oznacza to, że w danym momencie aktywny może być tylko jeden z tych projektów;
- wiersze 10–14: nadrzędny projekt Maven, który określa wersje większości zależności niezbędnych dla projektu;
- wiersze 19–23: biblioteka OpenJpa;
- wiersze 26–29: biblioteka Spring Data;
- wiersze 32–34: projekt konfiguracyjny warstwy JPA opiera się na projekcie konfiguracyjnym warstwy JDBC, który definiuje między innymi sterownik JDBC dla używanego SGBD oraz dane bazy danych, z której należy korzystać;
- wiersze 35–40: projekt konfiguracji warstwy JDBC zawiera bibliotekę [Spring JDBC], która została tutaj zastąpiona biblioteką [Spring Data JPA]. W związku z tym zaleca się, aby nie uwzględniać jej w zależnościach projektu. Jeśli jednak pozostanie, nie spowoduje to żadnych błędów;
Ostatecznie zależności są następujące:
![]() |
8.3.2. Konfiguracja Spring
![]() |
Klasa [ConfigJpa] konfiguruje projekt Spring w następujący sposób:
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 {
// dostawca JPA
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
OpenJpaVendorAdapter openJpaVendorAdapter = new OpenJpaVendorAdapter();
openJpaVendorAdapter.setShowSql(false);
openJpaVendorAdapter.setDatabase(Database.MYSQL);
openJpaVendorAdapter.setGenerateDdl(true);
return openJpaVendorAdapter;
}
// pakiety encji JPA
public final static String[] ENTITIES_PACKAGES = { "generic.jpa.entities.dbproduitscategories" };
// źródło danych
@Bean
public DataSource dataSource() {
// źródło danych TomcatJdbc
DataSource dataSource = new DataSource();
// konfiguracja dostępu JDBC
dataSource.setDriverClassName(ConfigJdbc.DRIVER_CLASSNAME);
dataSource.setUsername(ConfigJdbc.USER_DBPRODUITSCATEGORIES);
dataSource.setPassword(ConfigJdbc.PASSWD_DBPRODUITSCATEGORIES);
dataSource.setUrl(ConfigJdbc.URL_DBPRODUITSCATEGORIES);
// początkowo otwarte połączenia
dataSource.setInitialSize(5);
// wynik
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();
}
// Menedżer transakcji
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
Konfiguracja ta jest analogiczna do tej opisanej w paragrafie 6.3.2 dla implementacji Hibernate o nazwie JPA. Przedstawiamy jedynie różnice:
- wiersze 23–30: bean [jpaVendorAdapter] jest teraz zaimplementowany za pomocą OpenJpa;
8.4. Plik [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">
<!-- podmioty 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">
<!-- entities JPA -->
<class>generic.jpa.entities.dbproduits.Produit</class>
<exclude-unlisted-classes />
</persistence-unit>
</persistence>
- wiersz 4: jednostka trwałości powiązana z bazą [dbproduitscategories]. Może ona nosić dowolną nazwę (atrybut name);
- wiersze 6–10: pięć jednostek JPA, które mają być zarządzane;
- wiersze 13–17: kolejna jednostka trwałości powiązana z bazą [dbproduits]. OpenJpa umożliwia posiadanie pliku trwałości zawierającego wiele jednostek trwałości. EclipseLink tego nie pozwala. Przypominamy, że w przypadku Hibernate nie korzystaliśmy z pliku trwałości;
8.5. Warstwa testowa
![]() |
![]() |
Powyższe testy są identyczne z testami dla implementacji Spring JDBC, Spring JPA z Hibernate oraz Spring JPA i EclipseLink. W razie potrzeby należy zapoznać się z następującymi stronami:
- [JUnitTestCheckArguments]: punkt 4.11.1;
- [JUnitTestDao]: punkt 4.11.2;
- [JUnitTestPushTheLimits]: punkt 4.11.3;
- [JUnitTestProxies]: punkt 6.4.5;
Należy zastosować następujące konfiguracje uruchomieniowe:
![]() | ![]() |
![]() | ![]() |
Aby encje JPA zostały wzbogacone (woven) przez OpenJpa, aplikacje Java lub testy JUnit muszą być uruchamiane za pomocą agenta Java. Agent ten wzbogaci encje JPA, zanim zostaną one załadowane przez JVM i [http://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/ref_guide_pc_enhance.html]. Przyjrzyjmy się na przykład konfiguracji testu [JUnitTestDao]:
![]() |
- w zakładce [Arguments] [1] podaje się odniesienie do agenta Java w JVM zgodnie ze składnią [2]. Agentem Java jest archiwum [openjpa-<version>.jar], które znajduje się w folderze [<m2-repo>/org/apache/openjpa/<version>]. Folder <m2-repo> jest wskazany w konfiguracji Eclipse ([3] poniżej):
![]() |
W pliku [2], przedstawionym powyżej, wykorzystano zmienną [M2_REPO] zdefiniowaną przez użytkownika:
![]() |
Zmiennej [M2_REPO] nadano wartość widoczną w [3].
Wyniki uzyskane dla testów [JUnitTestDao] i [JUnitTestPushTheLimits] są następujące:
![]() |
![]() |
![]() |
- w przypadku [1], [JUnitTestPushTheLimits-EclipseLink]: 70,583 s;
- w [2], [JUnitTestPushTheLimits-Hibernate]: 78,945 s;
- w [3], [JUnitTestPushTheLimits-JDBC]: 36,09 s;
- w [4], [JUnitTestPushTheLimits-OpenJpa]: 80,394 s;
Wyniki konsoli uzyskane dla testu [JUnitTestProxies] są następujące:
Widać tutaj, że podczas uzyskiwania dostępu do pola [Categorie.produits] w kategorii typu PROXY oraz do pola [Produit.categorie] w produkcie typu PROXY, w obu przypadkach występuje wskaźnik null (wiersze 7 i 17).























