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

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

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

5 ответов


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

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

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

    атрибут имя. Остальные атрибуты и элементы являются необязательными. (Спецификации JPA). Так что это должно быть больше или меньше вашего минимального :
<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), поэтому вы обычно определяете свойства поставщика JPA, драйвера, url, пользователя и пароля. но имя свойства зависит от поставщика 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 предполагается, что не наша источнику будет обеспечен. В среде Java EE, если этот элемент не указан, по умолчанию используется JTA. В среде Java SE, если этот элемент не указан, по умолчанию RESOURCE_LOCAL можно предположить.

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

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

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

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

Да, вы можете без использования любого 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;
}

я смог создать 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() is важно так как в противном случае завод не будет построен, а потом getObject() возвращает null и вы гонитесь за NullPointerExceptions весь день. >:-(

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

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
}

вот решение без весны. Константы берутся из 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;
        }
    };
}

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

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

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

здесь PersistenceUnitInfo реализуется с помощью Spring-specific MutablePersistenceUnitInfo класса.

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