Создать 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.