Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to "parameterize" JPA database instance in persistence.xml?

I have a Java web application leveraging JPA. The database instance is specified in the persistence.xml file using the jta-data-source tag.

I would like to deploy a second copy of the web application on the same (glassfish) server, but pointed at a different database instance.

What is the best way to achieve this? I think ideally, I'd like to place a persistence.xml override file outside of the war (somewhere on the classpath?). I'm not exactly sure where to put it or how to define it in a way that it wouldn't confilt with my other instance. I can see us hosting a handful of instances in this manner (SaaS) and I'd like the configuration to be outside the deployed war so that it wouldn't become a maintenance issue. Sharing a database instance between clients is not an option for security reasons.

I'm sure this isn't a unique problem to our group. What are the best practices or solutions others are using to solve this problem?

like image 284
Vinnie Avatar asked Jun 08 '10 15:06

Vinnie


4 Answers

update:

http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/configuration.html

not sure if this can be set up in an appserver but i'll give it a go. only thing that worries me is management of the scope. the container manages the scope along transaction boundaries

//inject entity manager
@Inject("mySpecialEntityManager")
EntityManager em;

//then mark the actual factory method in the factory bean with    
@Produces("mySpecialEntityManager")

but then how to manage scope is the problem


2.2.2. Bootstrapping

The JPA specification defines a bootstrap procedure to access the EntityManagerFactory and the EntityManager. The bootstrap class is javax.persistence.Persistence, e.g.

Map configOverrides = new HashMap();

configOverrides.put("hibernate.hbm2ddl.auto", "create-drop");

EntityManagerFactory programmaticEmf =

Persistence.createEntityManagerFactory("manager1", configOverrides);

The first version is equivalent to the second with an empty map. The map version is a set of overrides that will take precedence over any properties defined in your persistence.xml files. All the properties defined in Section 2.2.1, “Packaging” can be passed to the createEntityManagerFactory method and there are a few additional ones:

*

  javax.persistence.provider to define the provider class used
*

  javax.persistence.transactionType to define the transaction type used (either JTA or RESOURCE_LOCAL)
*

  javax.persistence.jtaDataSource to define the JTA datasource name in JNDI
*

  javax.persistence.nonJtaDataSource to define the non JTA datasource name in JNDI
*

  javax.persistence.lock.timeout pessimistic lock timeout in milliseconds (Integer or String)
*

  javax.persistence.query.timeout query timeout in milliseconds (Integer or String)
*

  javax.persistence.sharedCache.mode corresponds to the share-cache-mode element defined in Section 2.2.1, “Packaging”.
like image 77
john sanders Avatar answered Oct 07 '22 10:10

john sanders


i guess you are already altering the copy in other things too ? (e.g. name of ear file)

If you use a build software like ant or maven you could use a placeholder inside the persistence.xml and create a different "copy" by just using different build parameters.

e.g. with maven

mvn clean install -DmyDatabaseName=db/somedb

like image 23
Michael Pralow Avatar answered Oct 07 '22 09:10

Michael Pralow


I would package two versions of the webapp and declare a specific datasource in the jta-data-source element of their respective persistence.xml (I don't think you can externalize this file, it is expected to be in WEB-INF/classes/META-INF/persistence.xml)

like image 1
Pascal Thivent Avatar answered Oct 07 '22 09:10

Pascal Thivent


What about storing a persistence.xml in the META-INF folder of a classes directory and then specifying that folder first in the classpath?

like image 1
Frank Klomp Avatar answered Oct 07 '22 08:10

Frank Klomp