Crear JPA EntityManager sin archivo de configuración persistence.xml
runtime (5)
¿Hay alguna manera de inicializar
EntityManager
sin una unidad de persistencia definida?
Debe definir al menos una unidad de persistencia en el descriptor de despliegue persistence.xml
.
¿Puedes dar todas las propiedades requeridas para crear un
Entitymanager
?
- El atributo de nombre es obligatorio. Los otros atributos y elementos son opcionales. (Especificación JPA). Así que este debería ser más o menos tu mínimo archivo
persistence.xml
:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
SOME_PROPERTIES
</persistence-unit>
</persistence>
En los entornos Java EE, los elementos
jta-data-source
ynon-jta-data-source
se utilizan para especificar el nombre JNDI global de la fuente de datos JTA y / o no JTA que utilizará el proveedor de persistencia.
Entonces, si su servidor de aplicaciones objetivo admite JTA (JBoss, Websphere, GlassFish), su persistence.xml
ve así:
<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 su servidor de aplicaciones objetivo no es compatible con JTA (Tomcat), su persistence.xml
ve así:
<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 su fuente de datos no está vinculada a un JNDI global (por ejemplo, fuera de un contenedor Java EE), entonces normalmente definiría las propiedades del proveedor, el controlador, la url, el usuario y la contraseña de JPA. Pero el nombre de la propiedad depende del proveedor de JPA. Entonces, para Hibernate como proveedor de JPA, su archivo persistence.xml
tendrá el siguiente aspecto:
<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 de transacción Atributo
En general, en entornos Java EE, un tipo de transacción de
RESOURCE_LOCAL
supone que se proporcionará un origen de datos no JTA. En un entorno Java EE, si este elemento no está especificado, el valor predeterminado es JTA. En un entorno Java SE, si no se especifica este elemento, se puede suponer un valor predeterminado deRESOURCE_LOCAL
.
- Para asegurar la portabilidad de una aplicación Java SE, es necesario enumerar explícitamente las clases de persistencia administradas que se incluyen en la unidad de persistencia (especificación JPA)
Necesito crear
EntityManager
partir de los valores especificados por el usuario en el tiempo de ejecución
Entonces usa esto:
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);
¿Hay alguna manera de inicializar EntityManager
sin una unidad de persistencia definida? ¿Puedes dar todas las propiedades requeridas para crear un administrador de entidades? Necesito crear EntityManager
partir de los valores especificados por el usuario en el tiempo de ejecución. La actualización de persistence.xml
y la recompilación no es una opción.
¡Cualquier idea sobre cómo hacer esto es más que bienvenida!
Aquí hay una solución sin Spring. Las constantes se toman 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();
Y la infame 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 JPA simple, suponiendo que tiene una implementación PersistenceProvider
(por ejemplo, Hibernate), puede usar el método PersistenceProvider # createContainerEntityManagerFactory (PersistenceUnitInfo, Map map) para EntityManagerFactory
una EntityManagerFactory
sin necesidad de un persistence.xml
.
Sin embargo, es molesto que tenga que implementar la interfaz PersistenceUnitInfo
, por lo que es mejor utilizar Spring o Hibernate, que son compatibles con bootstrapping JPA sin un archivo persistence.xml
:
this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(
this.persistenceUnitInfo,
getJpaPropertyMap()
);
Donde PersistenceUnitInfo se implementa mediante la clase MutablePersistenceUnitInfo específica de MutablePersistenceUnitInfo .
Echa un vistazo a este artículo para ver una buena demostración de cómo puedes lograr este objetivo con Hibernate.
Pude crear un EntityManager
con Hibernate y PostgreSQL usando puramente código Java (con una configuración de Spring) de la siguiente manera:
@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 llamada a LocalContainerEntityManagerFactoryBean.afterPropertiesSet()
es esencial ya que, de lo contrario, la fábrica nunca se getObject()
, y luego getObject()
devuelve null
y se está persiguiendo a NullPointerException
s durante todo el día. > :-(
Luego trabajó con el siguiente código:
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();
Donde mi entidad era esto:
@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
}
Sí, puedes hacerlo sin usar ningún archivo xml usando un resorte como este dentro de una clase @Configuration (o su configuración de primavera equivalente 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;
}