Создайте JPA EntityManager без сохранения.файл конфигурации xml
Существует ли способ инициализации EntityManager
без определенной единицы персистентности? Можете ли вы предоставить все необходимые свойства для создания менеджера сущностей? Мне нужно создать EntityManager
из заданных пользователем значений во время выполнения. Обновление persistence.xml
и перекомпиляция не являются опцией.
Любая идея о том, как это сделать, более чем приветствуется!
5 ответов:
Есть ли способ инициализировать
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 (или его эквивалента 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()
являетсясущественным , так как в противном случае фабрика никогда не будет построена, а затемgetObject()
возвращаетсяnull
, и вы преследуетеNullPointerException
s весь день. >:- (Затем он работал со следующим кодом:
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 info, Map map) для начальной загрузкиEntityManagerFactory
без необходимостиpersistence.xml
.Однако раздражает, что вам приходится реализовывать интерфейс
PersistenceUnitInfo
, поэтому вам лучше использовать Spring или Hibernate, которые оба поддерживают bootstrapping JPA без файлаpersistence.xml
:this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory( this.persistenceUnitInfo, getJpaPropertyMap() );
Где PersistenceUnitInfo реализуется классом Spring-specificMutablePersistenceUnitInfo .
Проверьтеэту статью для хорошей демонстрации того, как вы можете достичь этой цели с помощью Hibernate.