Cree EntityManager de JPA sin persistencia.archivo de configuración xml


¿Hay alguna forma de inicializar el EntityManager sin una unidad de persistencia definida? ¿Puede dar todas las propiedades necesarias para crear un entity manager? Necesito crear el EntityManager a partir de los valores especificados por el usuario en tiempo de ejecución. Actualizar persistence.xml y recompilar no es una opción.

Cualquier idea sobre cómo hacer esto es más que bienvenida!

Author: Martijn Pieters, 2010-01-02

5 answers

¿Hay alguna forma de inicializar el EntityManager sin una unidad de persistencia definida?

Debe definir al menos una unidad de persistencia en el descriptor de implementación persistence.xml.

Puede dar todas las propiedades necesarias para crear un Entitymanager?

  • Se requiere el atributo name. Los otros atributos y elementos son opcionales. (Especificación JPA). Así que esto debe ser más o menos su mínimo persistence.xml archivo:
<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 admite JTA (JBoss, Websphere, GlassFish), su persistence.xml se ve como:

<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 de destino no es compatible con JTA (Tomcat), su persistence.xml se 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á vinculado a un JNDI global (por ejemplo, fuera de un contenedor de Java EE), por lo que normalmente definiría las propiedades de proveedor, controlador, url, usuario y contraseña de JPA. Pero el nombre de la propiedad depende del proveedor JPA. Por lo tanto, para Hibernate como proveedor de JPA, su archivo persistence.xml se verá como:

<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 de RESOURCE_LOCAL asume que se proporcionará una fuente de datos no JTA. En un Java EE entorno, si no se especifica este elemento, el valor predeterminado es JTA. En un entorno Java SE, si no se especifica este elemento, se puede asumir un valor predeterminado de RESOURCE_LOCAL.

  • Para asegurar la portabilidad de una aplicación Java SE, es necesario listar explícitamente las clases de persistencia gestionadas que se incluyen en la unidad de persistencia (especificación JPA)

Necesito crear el EntityManager a partir de los valores especificados por el usuario en tiempo de ejecución

Así que 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);
 55
Author: Arthur Ronald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-26 07:28:34

Sí puede sin usar ningún archivo xml usando spring como este dentro de una clase @Configuration (o su equivalente spring 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;
}
 23
Author: Frank Orellana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-10 17:16:42

Pude crear un EntityManager con Hibernate y PostgreSQL usando puramente código Java (con una configuración de Resorte) 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 luego getObject() devuelve null y estás persiguiendo NullPointerException s 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 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
}
 15
Author: ArtB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-16 21:11:10

Aquí hay una solución sin resorte. 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;
        }
    };
}
 13
Author: Brice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-21 16:35:02

Con JPA simple, suponiendo que tenga una implementación PersistenceProvider (por ejemplo, Hibernate), puede usar el método PersistenceProvider#createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) para arrancar un EntityManagerFactory sin necesidad de un persistence.xml.

Sin embargo, es molesto que tenga que implementar la interfaz PersistenceUnitInfo, por lo que es mejor usar Spring o Hibernate que ambos admiten bootstrapping JPA sin un archivo persistence.xml:

this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(
    this.persistenceUnitInfo, 
    getJpaPropertyMap()
);

Donde el PersistenceUnitInfo está implementado por la clase MutablePersistenceUnitInfo específica de Spring.

Echa un vistazo a este artículo para una buena demostración de cómo puedes lograr este objetivo con Hibernate.

 4
Author: Vlad Mihalcea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-05 13:26:47