问题
I'm writing a Java SE (desktop) application that has to access different databases all of which will have the same data model (same schema, tables, etc.). I want to reuse the JPA Entities that I already use in a Java EE application that front each database.
To reuse the existing entity.jar file I'll have to repackage it with a different persistence.xml that has a resource_local data source. That's an build time inconvenience but not a big problem.
The problem is that my desktop application will be limited to using the datasource defined in the persistence.xml file. I could define multiple persistence units and select which one to use at runtime, but when a new database is added I'll have to change the persistence.xml and update all the desktop binaries.
I'd like to be able to define new data sources in a .properties file that each user could configure. Is there any way to override or add to the persistence units declared in the persistence.xml at runtime?
I don't want to build out the Java EE applications with web service interfaces just to support this desktop application. The Java EE applications have a different purpose and I want to keep the desktop functionality in the desktop application.
Thanks.
回答1:
You can create EntityManagerFactory at runtime by providing properties.
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(TRANSACTION_TYPE, PersistenceUnitTransactionType.RESOURCE_LOCAL.name());
properties.put(JDBC_DRIVER, driver);
properties.put(JDBC_URL, db_url);
properties.put(JDBC_USER, "userName");
properties.put(JDBC_PASSWORD, "password");
EntityManagerFactory factory = Persistence.createEntityManagerFactory("PERSISTENT_UNIT_NAME", properties);
Also you can try having a property file from which properties will be loaded at runtime into map. Therefore it will decouple the database configuration from code.
Edit : The property keys(JDBC_URL etc) are vendor specific, they should be replaced accordingly.
回答2:
Nayan,
I need to expand on your answer because it's not complete.
The confusing thing about using properties to dynamically create EntityManagers is that there are three createEntityManagerFactory() methods in JPA and all 3 take a persistenceunit name. I didn't realize that the properties override the persistenceunit name until I checked the JPA 2.0 spec. Section 9.4.3 says that the properties override the values given in the persistence.xml. It also shows what the standard property names are.
(The JavaDocs don't tell you what can go into the properties and they don't say that the properties override what is in persistence.xml. Another example where JavaDocs suck.)
Your example uses property names like "JDBC_URL" that aren't in the Java EE 6 API Javadocs. The JPA spec explains that vendor specific property names can be used in addition to the standard properties. The EclipseLink docs show what property names that implementation supports via the non-standard PersistenceUnitProperties class:
http://www.eclipse.org/eclipselink/api/2.3/index.html
So in order to have dynamic EntityManagers it is necessary to use vendor specific properties, so dynamic entity managers aren't portable. I guess you can't have everything.
One case where dynamic EntityManagers would be portable is through the use of the standard javax.persistence.jtaDataSource property. You would have to add the data source to your Java EE container, but that is as dynamic as you can be when running in a container. In Java SE it doesn't look like there are any portable, dynamic options.
The JavaDocs need to do a much better job of explaining how properties work with the createEntityManagerFactory() methods.
来源:https://stackoverflow.com/questions/9315593/how-can-i-make-a-jpa-application-access-different-databases