example - jpa java
JPA utilizando la alternativa "persistence.xml" (6)
Sé que con la instrucción:
Persistence.createEntityManagerFactory("persistence-unit-name");
El mecanismo de persistencia JPA lee el archivo "persistence.xml", busca la unidad de persistencia llamada "nombre-unidad de persistencia" y construye el EntityManagerFactory basado en él.
Mi pregunta es, ¿cómo puedo forzar a JPA a tomar un archivo diferente de "persistence.xml" ? por ejemplo, "persistence-test.xml".
Así que queremos tener 2 archivos persistence.xml
separados. Uno debe leerse solo por la configuración de producción, y el otro para pruebas. La idea es renombrar u ocultar los archivos de producción .
Solución de guerra
No ponga persistence.xml
en src/main/resources/META-INF/
. En su lugar, póngalo en src/main/webapp/WEB-INF/classes/META-INF/
. Esa es la ubicación donde debería estar el archivo y en este lugar no será visible mediante pruebas.
Esta solución funciona para mí en el entorno de Gradle, pero espero que en otros también lo haga.
Solución de tarro
Cambie el nombre del archivo de producción a persistence-ee.xml
. Ahora hemos terminado con la configuración de prueba. Para la producción debemos emplear algún procesamiento. Cada entorno puede tener su propio camino, así es como lo hago en Gradle:
tasks.withType(Jar) {
rename { fileName ->
fileName == "persistence-ee.xml" ? "persistence.xml" : fileName;
}
}
En mis aplicaciones, el archivo persistence.xml
para producción solo es necesario en el momento del despliegue, es decir, en los paquetes jar / war. Y estos son los únicos lugares donde este archivo es visible. Sin doble persistence
no pude iniciar mi base de datos. La razón principal fue el uso de jta-data-source
, la otra: 2 unidades de persistencia con nombre separadas.
En EclipseLink puedes hacer lo siguiente:
Properties pros = new Properties();
pros.setProperty(PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_XML,
"META-INF/persistence-alternative.xml");
EntityManagerFactory factory =
Persistence.createEntityManagerFactory("pu-name", pros);
No creo que puedas. El largo camino para hacer esto es:
- Cree una Fábrica que lea su
persistence-test.xml
y represente laspersistence-test.xml
unMap<String, String>
y. - Llame a
Persistence.createEntityManagerFactory(persistenceUnitName, Map properties)
. De esa manera, lee el mapa deproperties
en lugar de leerlo desdepersistence.xml
.
No hay una forma JPA estandarizada para hacer esto, aunque los proveedores de JPA individuales pueden proporcionar una forma. Sugeriría la forma estándar de tener una ruta de clase diferente para main y test.
Por ejemplo, si usa Maven y tiene dos archivos META-INF/persistence.xml
, uno en src/main/resources
y otro en src/test/resources
, las pruebas recogerán el de src/test/resources
, porque Maven coloca las clases / recursos de prueba por delante de las clases / recursos principales en el classpath. Puede configurar fácilmente Ant para que funcione de manera similar.
Si necesita una lógica más avanzada, considere usar el soporte JPA de Spring . Le permitirá lidiar con situaciones avanzadas como la integración de múltiples archivos persistence.xml .
Puede configurar Hibernate sin usar persistence.xml en Spring de esta manera:
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean()
{
Map<String, Object> properties = new Hashtable<>();
properties.put("javax.persistence.schema-generation.database.action",
"none");
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect"); //you can change this if you have a different DB
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(adapter);
factory.setDataSource(this.springJpaDataSource());
factory.setPackagesToScan("package name");
factory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
factory.setValidationMode(ValidationMode.NONE);
factory.setJpaPropertyMap(properties);
return factory;
}
Como no está utilizando persistence.xml, debe crear un bean que devuelva DataSource que especifique en el método anterior que establece el origen de datos:
@Bean
public DataSource springJpaDataSource()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl("jdbc:mysql://localhost/SpringJpa");
dataSource.setUsername("tomcatUser");
dataSource.setPassword("password1234");
return dataSource;
}
Luego usa la anotación @EnableTransactionManagement
sobre este archivo de configuración. Ahora, cuando pones esa anotación, debes crear un último bean:
@Bean
public PlatformTransactionManager jpaTransactionManager()
{
return new JpaTransactionManager(
this.entityManagerFactoryBean().getObject());
}
Ahora, no se olvide de usar @Transactional
Annotation sobre aquellos métodos que tratan con DB.
Por último, no olvide inyectar EntityManager
en su repositorio (esta clase de repositorio debe tener @Repository
anotación de @Repository
).
Si estaba usando OpenEJB para conducir sus pruebas, podría hacer exactamente lo que quiera con el proveedor de JPA que desee. Pregunta similar y la respuesta relacionada aquí:
¿Cómo hacer que Maven ignore mi main / resources / persistence.xml a favor de test / ...?