Existe-t-il un moyen d'initialiser la EntityManager
sans qu'une unité de persistance soit définie? Pouvez-vous donner toutes les propriétés requises pour créer un gestionnaire d'entités? Je dois créer la EntityManager
à partir des valeurs spécifiées par l'utilisateur au moment de l'exécution. La mise à jour du persistence.xml
et la recompilation ne sont pas une option.
Toute idée sur la façon de procéder est plus que bienvenue!
Existe-t-il un moyen d'initialiser le
EntityManager
sans qu'une unité de persistance soit définie?
Vous devez définir au moins une unité de persistance dans le descripteur de déploiement persistence.xml
.
Pouvez-vous donner toutes les propriétés requises pour créer un
Entitymanager
?
persistence.xml
minimal:<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
SOME_PROPERTIES
</persistence-unit>
</persistence>
Dans les environnements Java EE, les éléments
jta-data-source
etnon-jta-data-source
permettent de spécifier le nom JNDI global de la source de données JTA et/ou non JTA à utiliser par le fournisseur de persistance.
Ainsi, si votre serveur d'applications cible prend en charge JTA (JBoss, Websphere, GlassFish), votre persistence.xml
ressemble à ceci:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
<!--GLOBAL_JNDI_GOES_HERE-->
<jta-data-source>jdbc/myDS</jta-data-source>
</persistence-unit>
</persistence>
Si votre serveur d'applications cible ne prend pas en charge JTA (Tomcat), votre persistence.xml
ressemble à ceci:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
<!--GLOBAL_JNDI_GOES_HERE-->
<non-jta-data-source>jdbc/myDS</non-jta-data-source>
</persistence-unit>
</persistence>
Si votre source de données n'est pas liée à un JNDI global (par exemple, en dehors d'un conteneur Java EE), vous définissez généralement les propriétés du fournisseur JPA, du pilote, de l'URL, de l'utilisateur et du mot de passe. Mais nom de la propriété dépend du fournisseur JPA. Ainsi, pour Hibernate en tant que fournisseur JPA, votre fichier persistence.xml
ressemblera à ceci:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>br.com.persistence.SomeClass</class>
<properties>
<property name="hibernate.connection.driver_class" value="org.Apache.derby.jdbc.ClientDriver"/>
<property name="hibernate.connection.url" value="jdbc:derby://localhost:1527/EmpServDB;create=true"/>
<property name="hibernate.connection.username" value="APP"/>
<property name="hibernate.connection.password" value="APP"/>
</properties>
</persistence-unit>
</persistence>
Attribut Type de transaction
En général, dans les environnements Java EE, un type de transaction de
RESOURCE_LOCAL
suppose qu'une source de données non-JTA sera fournie. Dans un environnement Java EE, si cet élément n'est pas spécifié, la valeur par défaut est JTA. Dans un environnement Java SE, si cet élément n'est pas spécifié, une valeur par défaut deRESOURCE_LOCAL
peut être utilisée.
Je dois créer le
EntityManager
à partir des valeurs spécifiées par l'utilisateur lors de l'exécution
Alors utilisez ceci:
Map addedOrOverridenProperties = new HashMap();
// Let's suppose we are using Hibernate as JPA provider
addedOrOverridenProperties.put("hibernate.show_sql", true);
Persistence.createEntityManagerFactory(<PERSISTENCE_UNIT_NAME_GOES_HERE>, addedOrOverridenProperties);
Oui, vous pouvez utiliser aucun fichier xml utilisant spring comme ceci dans une classe @Configuration (ou son équivalent print config xml):
@Bean
public LocalContainerEntityManagerFactoryBean emf(){
properties.put("javax.persistence.jdbc.driver", dbDriverClassName);
properties.put("javax.persistence.jdbc.url", dbConnectionURL);
properties.put("javax.persistence.jdbc.user", dbUser); //if needed
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setPersistenceProviderClass(org.Eclipse.persistence.jpa.PersistenceProvider.class); //If your using Eclipse or change it to whatever you're using
emf.setPackagesToScan("com.yourpkg"); //The packages to search for Entities, line required to avoid looking into the persistence.xml
emf.setPersistenceUnitName(SysConstants.SysConfigPU);
emf.setJpaPropertyMap(properties);
emf.setLoadTimeWeaver(new ReflectiveLoadTimeWeaver()); //required unless you know what your doing
return emf;
}
J'ai pu créer un EntityManager
avec Hibernate et PostgreSQL uniquement à l'aide de code Java (avec une configuration Spring) comme suit:
@Bean
public DataSource dataSource() {
final PGSimpleDataSource dataSource = new PGSimpleDataSource();
dataSource.setDatabaseName( "mytestdb" );
dataSource.setUser( "myuser" );
dataSource.setPassword("mypass");
return dataSource;
}
@Bean
public Properties hibernateProperties(){
final Properties properties = new Properties();
properties.put( "hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect" );
properties.put( "hibernate.connection.driver_class", "org.postgresql.Driver" );
properties.put( "hibernate.hbm2ddl.auto", "create-drop" );
return properties;
}
@Bean
public EntityManagerFactory entityManagerFactory( DataSource dataSource, Properties hibernateProperties ){
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource( dataSource );
em.setPackagesToScan( "net.initech.domain" );
em.setJpaVendorAdapter( new HibernateJpaVendorAdapter() );
em.setJpaProperties( hibernateProperties );
em.setPersistenceUnitName( "mytestdomain" );
em.setPersistenceProviderClass(HibernatePersistenceProvider.class);
em.afterPropertiesSet();
return em.getObject();
}
L'appel à LocalContainerEntityManagerFactoryBean.afterPropertiesSet()
est essentiel car sinon, l'usine ne sera jamais construite et getObject()
retournera null
et vous poursuivrez après NullPointerException
toute la journée. > :-(
Cela a ensuite fonctionné avec le code suivant:
PageEntry pe = new PageEntry();
pe.setLinkName( "Google" );
pe.setLinkDestination( new URL( "http://www.google.com" ) );
EntityTransaction entTrans = entityManager.getTransaction();
entTrans.begin();
entityManager.persist( pe );
entTrans.commit();
Où mon entité était ceci:
@Entity
@Table(name = "page_entries")
public class PageEntry {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String linkName;
private URL linkDestination;
// gets & setters omitted
}
Voici une solution sans Spring . Les constantes sont extraites de org.hibernate.cfg.AvailableSettings
:
entityManagerFactory = new HibernatePersistenceProvider().createContainerEntityManagerFactory(
archiverPersistenceUnitInfo(),
ImmutableMap.<String, Object>builder()
.put(JPA_JDBC_DRIVER, JDBC_DRIVER)
.put(JPA_JDBC_URL, JDBC_URL)
.put(DIALECT, Oracle12cDialect.class)
.put(HBM2DDL_AUTO, CREATE)
.put(SHOW_SQL, false)
.put(QUERY_STARTUP_CHECKING, false)
.put(GENERATE_STATISTICS, false)
.put(USE_REFLECTION_OPTIMIZER, false)
.put(USE_SECOND_LEVEL_CACHE, false)
.put(USE_QUERY_CACHE, false)
.put(USE_STRUCTURED_CACHE, false)
.put(STATEMENT_BATCH_SIZE, 20)
.build());
entityManager = entityManagerFactory.createEntityManager();
Et l'infâme PersistenceUnitInfo
private static PersistenceUnitInfo archiverPersistenceUnitInfo() {
return new PersistenceUnitInfo() {
@Override
public String getPersistenceUnitName() {
return "ApplicationPersistenceUnit";
}
@Override
public String getPersistenceProviderClassName() {
return "org.hibernate.jpa.HibernatePersistenceProvider";
}
@Override
public PersistenceUnitTransactionType getTransactionType() {
return PersistenceUnitTransactionType.RESOURCE_LOCAL;
}
@Override
public DataSource getJtaDataSource() {
return null;
}
@Override
public DataSource getNonJtaDataSource() {
return null;
}
@Override
public List<String> getMappingFileNames() {
return Collections.emptyList();
}
@Override
public List<URL> getJarFileUrls() {
try {
return Collections.list(this.getClass()
.getClassLoader()
.getResources(""));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public URL getPersistenceUnitRootUrl() {
return null;
}
@Override
public List<String> getManagedClassNames() {
return Collections.emptyList();
}
@Override
public boolean excludeUnlistedClasses() {
return false;
}
@Override
public SharedCacheMode getSharedCacheMode() {
return null;
}
@Override
public ValidationMode getValidationMode() {
return null;
}
@Override
public Properties getProperties() {
return new Properties();
}
@Override
public String getPersistenceXMLSchemaVersion() {
return null;
}
@Override
public ClassLoader getClassLoader() {
return null;
}
@Override
public void addTransformer(ClassTransformer transformer) {
}
@Override
public ClassLoader getNewTempClassLoader() {
return null;
}
};
}
Avec JPA simple, en supposant que vous ayez une implémentation PersistenceProvider
(par exemple, Hibernate), vous pouvez utiliser la méthode PersistenceProvider # createContainerEntityManagerFactory (PersistenceUnitInfo info, map map) pour initialiser EntityManagerFactory
sans avoir besoin d'un persistence.xml
.
Cependant, il est embêtant de devoir implémenter l'interface PersistenceUnitInfo
, il est donc préférable d'utiliser Spring ou Hibernate, qui prennent tous deux en charge l'amorçage de JPA sans fichier persistence.xml
:
this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(
this.persistenceUnitInfo,
getJpaPropertyMap()
);
Où PersistenceUnitInfo est implémenté par la classe MutablePersistenceUnitInfo .
Découvrez cet article pour une belle démonstration de la façon dont vous pouvez atteindre cet objectif avec Hibernate.
DataNucleus JPA que j’utilise utilise aussi une manière de le faire dans sa documentation . Pas besoin de Spring, ni d'implémentation laide de PersistenceUnitInfo
.
Il suffit de faire comme suit
import org.datanucleus.metadata.PersistenceUnitMetaData;
import org.datanucleus.api.jpa.JPAEntityManagerFactory;
PersistenceUnitMetaData pumd = new PersistenceUnitMetaData("dynamic-unit", "RESOURCE_LOCAL", null);
pumd.addClassName("mydomain.test.A");
pumd.setExcludeUnlistedClasses();
pumd.addProperty("javax.persistence.jdbc.url", "jdbc:h2:mem:nucleus");
pumd.addProperty("javax.persistence.jdbc.user", "sa");
pumd.addProperty("javax.persistence.jdbc.password", "");
pumd.addProperty("datanucleus.schema.autoCreateAll", "true");
EntityManagerFactory emf = new JPAEntityManagerFactory(pumd, null);