¿Hay alguna forma de inicializar el EntityManager
sin una unidad de persistencia definida?
Debe definir al menos una unidad de persistencia en el persistence.xml
descriptor de implementación.
¿Puede dar todas las propiedades necesarias para crear un Entitymanager
?
- El atributo de nombre es obligatorio. Los demás atributos y elementos son opcionales. (Especificación JPA). Entonces este debería ser más o menos su
persistence.xml
archivo mínimo :
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
SOME_PROPERTIES
</persistence-unit>
</persistence>
En entornos Java EE, los elementos jta-data-source
y non-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 de destino es compatible con JTA (JBoss, Websphere, GlassFish), se persistence.xml
ve así:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
<jta-data-source>jdbc/myDS</jta-data-source>
</persistence-unit>
</persistence>
Si su servidor de aplicaciones de destino no es compatible con JTA (Tomcat), se persistence.xml
ve así:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_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), por lo general, definiría las propiedades de proveedor, controlador, URL, usuario y contraseña de JPA. Pero el nombre de la propiedad depende del proveedor de JPA. Entonces, para Hibernate como proveedor de JPA, su persistence.xml
archivo se verá así:
<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>
Atributo de tipo de transacción
En general, en entornos Java EE, un tipo de transacción RESOURCE_LOCAL
asume que se proporcionará una fuente de datos que no es JTA. En un entorno Java EE, si no se especifica este elemento, el valor predeterminado es JTA. En un entorno Java SE, si no se especifica este elemento, RESOURCE_LOCAL
se puede asumir un valor predeterminado de .
- 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 a EntityManager
partir de los valores especificados por el usuario en tiempo de ejecución
Entonces usa esto:
Map addedOrOverridenProperties = new HashMap();
addedOrOverridenProperties.put("hibernate.show_sql", true);
Persistence.createEntityManagerFactory(<PERSISTENCE_UNIT_NAME_GOES_HERE>, addedOrOverridenProperties);
Sí, puede sin usar ningún archivo xml usando un resorte como este dentro de una clase @Configuration (o su xml de configuración de resorte equivalente):
@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; }
fuente
properties
?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 el 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; } }; }
fuente
Pude crear un
EntityManager
con Hibernate y PostgreSQL usando puramente código Java (con una configuración de Spring) lo siguiente:@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 construye, y luegogetObject()
regresanull
y usted está persiguiendoNullPointerException
s todo el día. > :-(Luego funcionó 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 esta:
@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 }
fuente
Con JPA simple, asumiendo que tiene una
PersistenceProvider
implementación (por ejemplo, Hibernate), puede usar el método PersistenceProvider # createContainerEntityManagerFactory (PersistenceUnitInfo info, Map map) para arrancarEntityManagerFactory
sin necesidad de unpersistence.xml
.Sin embargo, es molesto que tenga que implementar la
PersistenceUnitInfo
interfaz, por lo que es mejor que use Spring o Hibernate, que admiten el arranque de JPA sin unpersistence.xml
archivo:this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory( this.persistenceUnitInfo, getJpaPropertyMap() );
Donde PersistenceUnitInfo es implementado por el MutablePersistenceUnitInfo específico de Spring clase .
Consulte este artículo para ver una buena demostración de cómo puede lograr este objetivo con Hibernate.
fuente
MutablePersistenceUnitInfo
no funciona ya que algunos métodos lanzan UnsupportedOperationException . Además, el artículo mencionado está un poco desactualizado:getPersistenceUnitRootUrl
no se puede devolver un valor nulo, de lo contrario, Hibernate no escanea la ruta de clases (Hibernate 5.2.8).getPersistenceUnitRootUrl
ogetJarFileUrls
. El último se siembra en stackoverflow.com/a/42372648/48136DataNucleus JPA que utilizo también tiene una forma de hacer esto en sus documentos . No es necesario Spring, ni una implementación desagradable de
PersistenceUnitInfo
.Simplemente haz lo siguiente
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);
fuente
También puede obtener un EntityManager usando PersistenceContext o la anotación Autowired, pero tenga en cuenta que no será seguro para subprocesos.
@PersistenceContext private EntityManager entityManager;
fuente