Erstellen Sie den JPA EntityManager ohne die Konfigurationsdatei persistence.xml

81

Gibt es eine Möglichkeit, die EntityManagerohne definierte Persistenzeinheit zu initialisieren ? Können Sie alle erforderlichen Eigenschaften angeben, um einen Entitätsmanager zu erstellen? Ich muss die zur EntityManagerLaufzeit aus den vom Benutzer angegebenen Werten erstellen . Das Aktualisieren persistence.xmlund Neukompilieren ist keine Option.

Jede Idee dazu ist mehr als willkommen!

javydreamercsw
quelle

Antworten:

57

Gibt es eine Möglichkeit, die EntityManagerohne definierte Persistenzeinheit zu initialisieren ?

Sie sollten mindestens eine Persistenzeinheit im persistence.xmlBereitstellungsdeskriptor definieren.

Können Sie alle erforderlichen Eigenschaften angeben, um eine zu erstellen Entitymanager?

  • Das Namensattribut ist erforderlich. Die anderen Attribute und Elemente sind optional. (JPA-Spezifikation). Das sollte also mehr oder weniger Ihre minimale persistence.xmlDatei sein:
<persistence>
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
        SOME_PROPERTIES
    </persistence-unit>
</persistence>

In Java EE-Umgebungen werden die Elemente jta-data-sourceund non-jta-data-sourceverwendet, um den globalen JNDI-Namen der JTA- und / oder Nicht-JTA-Datenquelle anzugeben, die vom Persistenzanbieter verwendet werden soll.

Wenn Ihr Zielanwendungsserver JTA (JBoss, Websphere, GlassFish) unterstützt, persistence.xmlsieht es folgendermaßen aus:

<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>

Wenn Ihr Zielanwendungsserver JTA (Tomcat) nicht unterstützt, persistence.xmlsieht es folgendermaßen aus:

<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>

Wenn Ihre Datenquelle nicht an eine globale JNDI gebunden ist (z. B. außerhalb eines Java EE-Containers), definieren Sie normalerweise die Eigenschaften von JPA-Anbieter, Treiber, URL, Benutzer und Kennwort. Der Name der Eigenschaft hängt jedoch vom JPA-Anbieter ab. Für Hibernate als JPA-Anbieter persistence.xmlsieht Ihre Datei also folgendermaßen aus:

<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>

Transaktionstypattribut

In Java EE-Umgebungen wird bei einem Transaktionstyp im Allgemeinen RESOURCE_LOCALdavon ausgegangen, dass eine Nicht-JTA-Datenquelle bereitgestellt wird. Wenn in einer Java EE-Umgebung dieses Element nicht angegeben ist, ist der Standardwert JTA. Wenn in einer Java SE-Umgebung dieses Element nicht angegeben ist, kann ein Standardwert von RESOURCE_LOCALangenommen werden.

  • Um die Portabilität einer Java SE-Anwendung sicherzustellen, müssen die verwalteten Persistenzklassen, die in der Persistenzeinheit enthalten sind (JPA-Spezifikation) , explizit aufgelistet werden.

Ich muss die zur EntityManagerLaufzeit aus den vom Benutzer angegebenen Werten erstellen

Verwenden Sie also Folgendes:

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);
Arthur Ronald
quelle
Hallo habe ich versucht , Ihre Lösung, aber auf Probleme stoßen, könnten Sie bitte meine Frage prüfen: stackoverflow.com/questions/3935394/...
Staplers
Aber ... die Frage war, wie man einen JPA EntityManager ohne persistence.xml erstellt. Diese Antwort ist gut, aber es wird immer noch persistence.xml verwendet, oder?
Joshua Davis
Werden sie in der JavaEE-Umgebung beim Erstellen einer EntityManagerFactory von EJB / JPA verwaltet?
Anthony Vinay
29

Ja, Sie können ohne Verwendung einer XML-Datei mit spring wie diesem in einer @ Configuration-Klasse (oder der entsprechenden Spring-Konfigurations-XML) Folgendes tun:

@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;
}
Frank Orellana
quelle
Welches Objekt ist properties?
Bedrohung
Es ist ein einfaches java.util.Properties-Objekt
Frank Orellana
20

Hier ist eine Lösung ohne Frühling. Konstanten werden entnommen aus 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();

Und das berüchtigte 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;
        }
    };
}
Brice
quelle
3
Dies hat mir sehr geholfen, da es mir geholfen hat, den Aufwand für die Verwendung von Arquillian in einigen Testfällen zu vermeiden!
Cljk
18

Ich konnte EntityManagermit Hibernate und PostgreSQL ausschließlich mit Java-Code (mit einer Spring-Konfiguration) Folgendes erstellen :

@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();
}

Der Anruf bei LocalContainerEntityManagerFactoryBean.afterPropertiesSet()ist wichtig, da sonst die Fabrik nie gebaut wird und dann getObject()zurückkehrt nullund Sie den NullPointerExceptionganzen Tag hinterher jagen . > :-(

Es funktionierte dann mit folgendem Code:

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();

Wo meine Entität war diese:

@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
}
Schlitten
quelle
2
Schöne Alternative für den Ruhezustand.
Javydreamercsw
8

Mit einfachem JPA können Sie unter der Annahme, dass Sie eine PersistenceProviderImplementierung haben (z. B. Hibernate), die PersistenceProvider # createContainerEntityManagerFactory-Methode (PersistenceUnitInfo info, Map map) verwenden, um eine EntityManagerFactoryzu booten, ohne eine zu benötigen persistence.xml.

Es ist jedoch ärgerlich, dass Sie die PersistenceUnitInfoSchnittstelle implementieren müssen , sodass Sie besser Spring oder Hibernate verwenden sollten, die beide das Bootstrapping von JPA ohne persistence.xmlDatei unterstützen:

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

Wobei die PersistenceUnitInfo von der Spring-spezifischen MutablePersistenceUnitInfo- Klasse implementiert wird .

In diesem Artikel erfahren Sie, wie Sie dieses Ziel mit Hibernate erreichen können.

Vlad Mihalcea
quelle
Die Verwendung MutablePersistenceUnitInfofunktioniert nicht, da einige Methoden UnsupportedOperationException auslösen . Auch der erwähnte Artikel ist etwas veraltet: getPersistenceUnitRootUrlKann nicht null zurückgeben, sonst scannt Hibernate den Klassenpfad nicht (Hibernate 5.2.8).
Brice
1
Ich habe mich ein bisschen geirrt, der Artikel ist in dieser Hinsicht nicht veraltet, da der Code eine Liste von Entitäten übergibt und kein Paket-Scannen verwendet. Für das automatische Scannen von Entitäten muss jedoch entweder getPersistenceUnitRootUrl oder implementiert werden getJarFileUrls. Letzteres
Brice
0

DataNucleus JPA, das ich verwende, hat auch eine Möglichkeit, dies in seinen Dokumenten zu tun . Keine Notwendigkeit für Frühling oder hässliche Implementierung vonPersistenceUnitInfo .

Gehen Sie einfach wie folgt vor

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);

quelle
0

Sie können einen EntityManager auch mithilfe von PersistenceContext oder Autowired Annotation abrufen. Beachten Sie jedoch, dass er nicht threadsicher ist.

@PersistenceContext
private EntityManager entityManager;
Ankit Sharma
quelle