Creare JPA EntityManager senza file di configurazione persistence.xml
-
22-09-2019 - |
Domanda
C'è un modo per inizializzare l'EntityManager
senza un'unità di persistenza definita? Puoi dare tutte le proprietà richieste per creare un gestore di entità? Ho bisogno di creare il EntityManager
dai valori specificati dell'utente in fase di esecuzione. Aggiornamento del persistence.xml
e ricompilando non è un'opzione.
Qualche idea su come fare questo è più che benvenuto!
Soluzione
C'è un modo per inizializzare l'
EntityManager
senza un'unità di persistenza definita?
È necessario definire almeno un'unità di persistenza nel descrittore di distribuzione persistence.xml
.
Si può dare tutte le proprietà richieste per creare un
Entitymanager
?
- è richiesto L'attributo name. Gli altri attributi ed elementi sono opzionali. (Specifica JPA). Quindi questo dovrebbe essere più o meno il file
persistence.xml
minima:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
SOME_PROPERTIES
</persistence-unit>
</persistence>
In ambienti Java EE, gli elementi
jta-data-source
enon-jta-data-source
vengono utilizzati per specificare il nome JNDI globale del JTA e / o fonte di dati non-JTA per essere utilizzato dal provider di persistenza.
Così, se il server di destinazione Applicazione supporta JTA (JBoss, Websphere, GlassFish), il vostro persistence.xml
appare come:
<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>
Se il server di destinazione applicazione non supporta JTA (Tomcat), il vostro persistence.xml
appare come:
<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>
Se l'origine dati non è vincolata ad un JNDI globale (per esempio, al di fuori di un contenitore Java EE), in modo da di solito definire le proprietà del provider JPA, del driver, url, utente e password. Ma nome della proprietà dipende dal provider JPA. Così, per Hibernate come provider JPA, la tua volontà di file persistence.xml
appare come:
<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>
Tipo di transazione attributo
In generale, in ambienti Java EE, una transazione di tipo di
RESOURCE_LOCAL
presuppone che sarà fornito un non-JTA origine dati. In un ambiente Java EE, se questo elemento non è specificato, il valore predefinito è JTA. In un ambiente Java SE, se questo elemento non è specificato, il valore predefinitoRESOURCE_LOCAL
può essere assunto.
- Per assicurare la portabilità di un'applicazione Java SE, è necessario elencare esplicitamente le classi di persistenza gestiti che sono inclusi nel gruppo di persistenza (specifica JPA)
ho bisogno di creare il
EntityManager
dai valori specificati dell'utente in fase di esecuzione
Quindi, utilizzare questo:
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);
Altri suggerimenti
Sì, è possibile senza l'uso di file XML usando primavera come questo all'interno di una classe @Configuration (o il suo equivalente config primavera 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;
}
Sono stato in grado di creare un EntityManager
con Hibernate e PostgreSQL puramente utilizzando il codice Java (con una configurazione di Spring) il seguente:
@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();
}
La chiamata al LocalContainerEntityManagerFactoryBean.afterPropertiesSet()
è essenziale in quanto altrimenti la fabbrica non viene mai costruito, e poi ritorna getObject()
null
e ti inseguono dopo NullPointerException
s tutto il giorno. >: - (
E 'poi lavorato con il seguente codice:
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();
Dove il mio soggetto è stato questo:
@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
}
Ecco una soluzione senza molla.
Costanti sono presi da 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();
E il famigerato 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;
}
};
}
Con pianura APP, a patto che abbiate un'implementazione PersistenceProvider
(ad es Hibernate), è possibile utilizzare il PersistenceProvider # createContainerEntityManagerFactory (PersistenceUnitInfo informazioni, mappa mappa) metodo per bootstrap un EntityManagerFactory
senza bisogno di un persistence.xml
.
Tuttavia, è fastidioso che si deve implementare l'interfaccia PersistenceUnitInfo
, così si è meglio utilizzare primavera o Hibernate quale sia il supporto bootstrap JPA senza un file persistence.xml
:
this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(
this.persistenceUnitInfo,
getJpaPropertyMap()
);
Dove è implementato il PersistenceUnitInfo dallo specifico-Spring MutablePersistenceUnitInfo classe.
questo articolo per una bella dimostrazione di come si può raggiungere questo obiettivo con Hibernate.
DataNucleus APP che io uso è anche un modo di fare questo nella sua docs . Non c'è bisogno di primavera, o brutto attuazione PersistenceUnitInfo
.
È sufficiente fare come segue
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);