Создайте JPA EntityManager без файла конфигурации persistence.xml.
-
22-09-2019 - |
Вопрос
Есть ли способ инициализировать EntityManager
без определения единицы персистентности?Можете ли вы указать все необходимые свойства для создания менеджера сущностей?мне нужно создать EntityManager
из указанных пользователем значений во время выполнения.Обновление persistence.xml
и перекомпиляция не вариант.
Любая идея о том, как это сделать, более чем приветствуется!
Решение
Есть ли способ инициализировать
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), вы обычно определяете свойства поставщика 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
предполагает, что будет предоставлен источник данных, отличный от JTA.Если в среде 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 (или его эквивалентного XML-файла конфигурации Spring):
@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()
является существенный иначе завод никогда не будет построен, и тогда 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
}
Вот решение без 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;
}
};
}
С простым JPA, предполагая, что у вас есть PersistenceProvider
реализация (например,Спящий режим), вы можете использовать PersistenceProvider#createContainerEntityManagerFactory (информация PersistenceUnitInfo, карта карты) метод загрузки EntityManagerFactory
без необходимости persistence.xml
.
Однако раздражает то, что вам приходится реализовывать PersistenceUnitInfo
интерфейс, поэтому вам лучше использовать Spring или Hibernate, которые поддерживают загрузку JPA без persistence.xml
файл:
this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(
this.persistenceUnitInfo,
getJpaPropertyMap()
);
Где PersistenceUnitInfo реализуется специфичным для Spring MutablePersistenceUnitInfo сорт.
Проверить Эта статья за красивую демонстрацию того, как можно достичь этой цели с помощью Hibernate.
DataNucleus JPA, который я использую, также имеет способ сделать это. в его документах.Нет необходимости в Spring или уродливой реализации PersistenceUnitInfo
.
Просто сделайте следующее
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);