8. Spring Data JPA OpenJpa
8.1. Introducción
Retomamos la arquitectura anterior, que ahora implementamos con una capa JPA / OpenJpa.
![]() |
8.2. Configuración del entorno de trabajo
Con STS, descargue el proyecto [myql-config-jpa-eclipselink] [1-4]:
![]() |
y, a continuación, importe el proyecto [mysl-config-jpa-openjpa] [5] que se encuentra en la carpeta [<exemples>/spring-database-config/mysql/eclipse] [6]:
![]() |
Una vez hecho esto, reinicie el entorno Maven (Alt-F5) de todos los proyectos presentes en [Package Explorer]:
![]() |
A continuación, para comprobar el entorno de trabajo, ejecute la configuración de ejecución denominada [spring-jpa-generic-JUnitTestDao-openjpa]:
![]() | ![]() |
Esta configuración ejecuta la prueba [JUnitTestDao]. Esta prueba debe completarse con éxito:
![]() |
8.3. El proyecto de configuración de la capa JPA
![]() |
Este proyecto tiene como función configurar la capa JPA de la arquitectura que se muestra a continuación:
![]() |
8.3.1. Configuración de Maven
El proyecto es un proyecto Maven y está configurado mediante el siguiente archivo [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>
<!-- dependencias variables ********************************************** -->
<!-- JPA proveedor -->
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<version>2.3.0</version>
</dependency>
<!-- dependencias constantes ********************************************** -->
<!-- Spring Data -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<!-- configuración heredada 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>
- líneas 5-7: el artefacto Maven generado por este proyecto. Es el mismo que el del proyecto [mysql-config-jpa-hibernate]. Esto significa que solo uno de estos proyectos puede estar activo en un momento dado;
- líneas 10-14: el proyecto Maven principal que define la mayoría de las dependencias necesarias para el proyecto version;
- líneas 19-23: la biblioteca OpenJpa;
- líneas 26-29: la biblioteca Spring Data;
- líneas 32-34: el proyecto de configuración de la capa JPA se basa en el de configuración de la capa JDBC, que define, entre otras cosas, el controlador JDBC del SGBD utilizado y las coordenadas de la base de datos que se va a utilizar;
- líneas 35-40: el proyecto de configuración de la capa JDBC incluye la biblioteca [Spring JDBC], que aquí se sustituye por la biblioteca [Spring Data JPA]. Por lo tanto, se indica que no se incluya en las dependencias del proyecto. Sin embargo, si se mantiene, no provoca errores;
Al final, las dependencias son las siguientes:
![]() |
8.3.2. Configuración de Spring
![]() |
La clase [ConfigJpa] configura el proyecto Spring de la siguiente manera:
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 {
// el proveedor JPA
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
OpenJpaVendorAdapter openJpaVendorAdapter = new OpenJpaVendorAdapter();
openJpaVendorAdapter.setShowSql(false);
openJpaVendorAdapter.setDatabase(Database.MYSQL);
openJpaVendorAdapter.setGenerateDdl(true);
return openJpaVendorAdapter;
}
// paquetes de entidades JPA
public final static String[] ENTITIES_PACKAGES = { "generic.jpa.entities.dbproduitscategories" };
// fuente de datos
@Bean
public DataSource dataSource() {
// fuente de datos TomcatJdbc
DataSource dataSource = new DataSource();
// configuración de acceso JDBC
dataSource.setDriverClassName(ConfigJdbc.DRIVER_CLASSNAME);
dataSource.setUsername(ConfigJdbc.USER_DBPRODUITSCATEGORIES);
dataSource.setPassword(ConfigJdbc.PASSWD_DBPRODUITSCATEGORIES);
dataSource.setUrl(ConfigJdbc.URL_DBPRODUITSCATEGORIES);
// conexiones abiertas inicialmente
dataSource.setInitialSize(5);
// resultado
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();
}
// Gestor de transacciones
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
Esta configuración es análoga a la detallada en el apartado 6.3.2, para la implementación JPA de Hibernate. Solo detallamos las diferencias:
- líneas 23-30: el bean [jpaVendorAdapter] se implementa ahora con OpenJpa;
8.4. El archivo [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">
<!-- entidades 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">
<!-- Entidades JPA -->
<class>generic.jpa.entities.dbproduits.Produit</class>
<exclude-unlisted-classes />
</persistence-unit>
</persistence>
- línea 4: la unidad de persistencia vinculada a la base [dbproduitscategories]. Puede tener cualquier nombre (atributo name);
- líneas 6-10: las cinco entidades JPA que se deben gestionar;
- líneas 13-17: otra unidad de persistencia vinculada a la base [dbproduits]. OpenJpa permite tener un archivo de persistencia con varias unidades de persistencia. EclipseLink no lo permite. Recordemos que con Hibernate no se utilizó ningún archivo de persistencia;
8.5. La capa de pruebas
![]() |
![]() |
Las pruebas anteriores son idénticas a las de las implementaciones Spring JDBC, Spring JPA Hibernate y Spring JPA EclipseLink. Consulte las siguientes páginas si es necesario:
- [JUnitTestCheckArguments]: apartado 4.11.1;
- [JUnitTestDao]: apartado 4.11.2;
- [JUnitTestPushTheLimits]: apartado 4.11.3;
- [JUnitTestProxies]: apartado 6.4.5;
Las configuraciones de ejecución que se deben utilizar son las siguientes:
![]() | ![]() |
![]() | ![]() |
Para que las entidades JPA sean enriquecidas (woven) por OpenJpa, es necesario que las aplicaciones Java o las pruebas JUnit se ejecuten con un agente Java. Este enriquecerá las entidades JPA antes de que sean cargadas por JVM [http://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/ref_guide_pc_enhance.html]. Veamos, por ejemplo, la configuración de la prueba [JUnitTestDao]:
![]() |
- en la pestaña [Arguments] [1], se proporciona la referencia del agente Java a JVM según la sintaxis [2]. El agente Java es el archivo [openjpa-<version>.jar] que se encuentra en la carpeta [<m2-repo>/org/apache/openjpa/<version>]. La carpeta <m2-repo> se indica en la configuración de Eclipse ([3] a continuación):
![]() |
En [2], arriba, se ha utilizado una variable [M2_REPO] definida por el usuario:
![]() |
Se ha asignado a la variable [M2_REPO] el valor visible en [3].
Los resultados obtenidos para las pruebas [JUnitTestDao] y [JUnitTestPushTheLimits] son los siguientes:
![]() |
![]() |
![]() |
- en [1], [JUnitTestPushTheLimits-EclipseLink]: 70,583 s;
- en [2], [JUnitTestPushTheLimits-Hibernate]: 78,945 s;
- en [3], [JUnitTestPushTheLimits-JDBC]: 36,09 s;
- en [4], [JUnitTestPushTheLimits-OpenJpa]: 80,394 s;
Los resultados de la consola obtenidos para la prueba [JUnitTestProxies] son los siguientes:
Aquí vemos que, al acceder al campo [Categorie.produits] de una categoría de tipo PROXY y al campo [Produit.categorie] de un producto de tipo PROXY, se obtiene un puntero nulo en ambos casos (líneas 7 y 17).























