是否有一种方法可以在没有定义持久性单元的情况下初始化EntityManager
?您能否提供创建实体管理器所需的所有必要属性?我需要根据用户在运行时指定的值创建EntityManager
。更新persistence.xml
并重新编译不是选项。
如果您有任何想法,请随时分享!
是否有一种方法可以在没有定义持久性单元的情况下初始化EntityManager
?您能否提供创建实体管理器所需的所有必要属性?我需要根据用户在运行时指定的值创建EntityManager
。更新persistence.xml
并重新编译不是选项。
如果您有任何想法,请随时分享!
有没有一种方法可以在没有定义持久化单元的情况下初始化
EntityManager
?
应该在persistence.xml
部署描述符中定义至少一个持久化单元。
你能给出创建一个
Entitymanager
所需的所有属性吗?
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
元素用于指定持久性提供者将使用的JTA和/或非JTA数据源的全局JNDI名称。
因此,如果您的目标应用服务器支持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
。
我需要在运行时从用户指定的值创建
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文件的情况下,通过在@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;
}
properties
是什么对象? - user1191027以下是不使用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;
}
};
}
我使用Java代码(通过Spring配置)纯粹地创建了一个与Hibernate和PostgreSQL交互的EntityManager
:
@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
}
使用纯JPA,假设您有一个 PersistenceProvider
实现(例如Hibernate),您可以使用 PersistenceProvider#createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) 方法来引导一个不需要 persistence.xml
的 EntityManagerFactory
。
然而,要实现 PersistenceUnitInfo
接口是很烦人的,因此最好使用Spring或Hibernate,它们都支持在没有 persistence.xml
文件的情况下引导JPA:
this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(
this.persistenceUnitInfo,
getJpaPropertyMap()
);
在Spring框架中,PersistenceUnitInfo由特定于Spring的MutablePersistenceUnitInfo类实现。
MutablePersistenceUnitInfo
是不起作用的,因为一些方法抛出UnsupportedOperationException。此外,提到的文章有点过时:getPersistenceUnitRootUrl
不能返回null,否则Hibernate将无法扫描类路径(Hibernate 5.2.8)。 - bric3getPersistenceUnitRootUrl
或getJarFileUrls
之一。后者在https://dev59.com/6XI-5IYBdhLWcg3wKE-x#42372648中提到。 - bric3我使用的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);