简体   繁体   中英

JPA using alternative “persistence.xml”

I know that with the instruction:

Persistence.createEntityManagerFactory("persistence-unit-name");

The JPA persistence mechanism reads the "persistence.xml" file, looks for the persistence unit called "persistence-unit-name", and constructs the EntityManagerFactory based on it.

My question is, how can I force JPA to take a file different from "persistence.xml" ?? for example, "persistence-test.xml".

There is no standardized JPA way to do this, although individual JPA providers may provide a way. I would suggest the standard way to have a different class path for main and test.

For example, if you use Maven, and you have two META-INF/persistence.xml files, one in src/main/resources and one in src/test/resources , tests will pick up the one in src/test/resources , because Maven puts test classes / resources ahead of main classes / resources in the classpath. You can easily configure Ant to work in similar ways.

If you need more advanced logic, consider using Spring's JPA support . It will let you deal with advanced situations like integrating multiple persistence.xml files .

In EclipseLink you can do the following:

Properties pros = new Properties();

pros.setProperty(PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_XML, 
                 "META-INF/persistence-alternative.xml");


EntityManagerFactory factory = 
    Persistence.createEntityManagerFactory("pu-name", pros);

I don't think you can. The long way of doing this is:

So we want to have 2 separate persistence.xml files. One should be read only by production configuration, and the other for tests. The idea is to rename or hide the production files.

War solution

Don't put persistence.xml in src\\main\\resources\\META-INF\\ . Instead put it into src\\main\\webapp\\WEB-INF\\classes\\META-INF\\ . That's the location where the file should be and in this place it won't be visible by tests.

This solution works for me in gradle environment, but I hope in others would do too.

Jar solution

Rename the production file to persistence-ee.xml . Now we're done with the test configuration. For production we must employ some processing. Each environment may have its own way, that's how I do it in gradle:

tasks.withType(Jar) {
  rename { fileName ->
    fileName == "persistence-ee.xml" ? "persistence.xml" : fileName;
  }
}

In my applications having the persistence.xml file for production is necessary only at deployment time, that is in jar/war packages. And these are the only places where this file is visible. Without double persistence I couldn't start my database. The main reason was using jta-data-source , the other: 2 separate named persistence units.

You can configure Hibernate without using persistence.xml at all in Spring like like this:

@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;
}

Since you are not using persistence.xml, you should create a bean that returns DataSource which you specify in the above method that sets the data source:

@Bean
public DataSource springJpaDataSource()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl("jdbc:mysql://localhost/SpringJpa");
dataSource.setUsername("tomcatUser");
dataSource.setPassword("password1234");
return dataSource;
}

Then you use @EnableTransactionManagement annotation over this configuration file. Now when you put that annotation, you have to create one last bean:

@Bean
public PlatformTransactionManager jpaTransactionManager()
{
return new JpaTransactionManager(
this.entityManagerFactoryBean().getObject());
}

Now, don't forget to use @Transactional Annotation over those method that deal with DB.

Lastly, don't forget to inject EntityManager in your repository (This repository class should have @Repository annotation over it).

If you were using OpenEJB to drive your testing, you could do exactly what you want using whichever JPA provider you want. Similar question and the related answer here:

How to instruct Maven to ignore my main/resources/persistence.xml in favor of test/...?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM