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!

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

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

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

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
}

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.


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

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;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.