Создать JPA EntityManager без файла конфигурации persistence.xml

Есть ли способ инициализировать EntityManager без единицы определения продолжительности? Можете ли вы предоставить все необходимые свойства для создания диспетчера объектов? Мне нужно создать EntityManager из заданных пользователем значений во время выполнения. Обновление persistence.xml и перекомпиляция не является вариантом.

Любая идея о том, как это сделать, более чем приветствуется!

Ответ 1

Есть ли способ инициализировать EntityManager без определенной единицы сохранения?

В дескрипторе развертывания persistence.xml вы должны определить не менее один блок персистентности.

Можете ли вы предоставить все необходимые свойства для создания EntityManager?

  • Требуется атрибут name. Другие атрибуты и элементы являются необязательными. (Спецификация JPA). Таким образом, это должен быть более или менее минимальный persistence.xml файл:
<persistence>
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
        SOME_PROPERTIES
    </persistence-unit>
</persistence>

В средах Java EE элементы jta-data-source и non-jta-data-source используются для указания глобального имени JNDI источника данных JTA и/или не-JTA, которое будет использоваться поставщиком сохранения.

Итак, если ваш целевой сервер приложений поддерживает JTA (JBoss, Websphere, GlassFish), ваш persistence.xml выглядит так:

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

Если ваш целевой сервер приложений не поддерживает JTA (Tomcat), ваш persistence.xml выглядит так:

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

Если ваш источник данных не привязан к глобальному JNDI (например, вне контейнера Java EE), вы обычно определяете свойства поставщика, драйвера, URL-адреса, пользователя и пароля JPA. Но имя свойства зависит от поставщика JPA. Итак, для Hibernate как поставщика JPA ваш файл persistence.xml будет выглядеть так:

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

Атрибут типа транзакции

В общем, в средах Java EE тип транзакции RESOURCE_LOCAL предполагает, что будет предоставлен источник данных, не относящийся к JTA. В среде Java EE, если этот элемент не указан, по умолчанию используется JTA. В среде Java SE, если этот элемент не указан, может быть принято значение по умолчанию RESOURCE_LOCAL.

  • Чтобы обеспечить переносимость приложения Java SE, , необходимо явно указать управляемые классы персистентности, которые включены в блок персистентности (спецификация JPA)

Мне нужно создать EntityManager из заданных пользователем значений во время выполнения

Поэтому используйте это:

Map addedOrOverridenProperties = new HashMap();

// Let suppose we are using Hibernate as JPA provider
addedOrOverridenProperties.put("hibernate.show_sql", true);

Persistence.createEntityManagerFactory(<PERSISTENCE_UNIT_NAME_GOES_HERE>, addedOrOverridenProperties);

Ответ 2

Да, вы можете без использования любого xml файла с помощью spring, как это, внутри класса @Configuration (или его эквивалентного 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;
}

Ответ 3

Мне удалось создать EntityManager с Hibernate и PostgreSQL, используя только код Java (с конфигурацией Spring):

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

Вызов LocalContainerEntityManagerFactoryBean.afterPropertiesSet() существенный, поскольку в противном случае factory никогда не будет создан, а затем getObject() вернет null и вы будете преследовать после NullPointerException весь день. > : - (

Затем он работал со следующим кодом:

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

Где моя сущность:

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

Ответ 4

Здесь решение без Spring. Константы взяты из 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();

И печально известный 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;
        }
    };
}

Ответ 5

При использовании простой JPA, если у вас есть реализация PersistenceProvider (например, Hibernate), вы можете использовать PersistenceProvider # createContainerEntityManagerFactory (информация о PersistenceUnitInfo, карта карты) для загрузки EntityManagerFactory без необходимости <<22 > .

Однако раздражает, что вам нужно реализовать интерфейс PersistenceUnitInfo, поэтому вам лучше использовать Spring или Hibernate, которые поддерживают загрузку JPA без файла persistence.xml:

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

Где PersistenceUnitInfo реализуется Spring -специфическим MutablePersistenceUnitInfo.

Откажитесь от этой статьи за хорошую демонстрацию того, как вы можете достичь этой цели с помощью Hibernate.