创建没有 persistence.xml 配置文件的 JPA EntityManager
Posted
技术标签:
【中文标题】创建没有 persistence.xml 配置文件的 JPA EntityManager【英文标题】:Create JPA EntityManager without persistence.xml configuration file 【发布时间】:2010-12-31 16:08:55 【问题描述】:有没有办法在没有定义持久性单元的情况下初始化EntityManager
?您能否提供创建实体管理器所需的所有属性?我需要在运行时根据用户指定的值创建EntityManager
。更新 persistence.xml
并重新编译不是一种选择。
欢迎任何关于如何做到这一点的想法!
【问题讨论】:
【参考方案1】:使用普通 JPA,假设您有一个 PersistenceProvider
实现(例如 Hibernate),您可以使用 PersistenceProvider#createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) 方法引导 EntityManagerFactory
而不需要 persistence.xml
。
但是,您必须实现 PersistenceUnitInfo
接口很烦人,因此您最好使用 Spring 或 Hibernate,它们都支持在没有 persistence.xml
文件的情况下引导 JPA:
this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(
this.persistenceUnitInfo,
getJpaPropertyMap()
);
PersistenceUnitInfo 由 Spring 特定的 MutablePersistenceUnitInfo 类实现。
【讨论】:
使用MutablePersistenceUnitInfo
不适用于某些方法throw UnsupportedOperationException。另外提到的article 有点过时了:getPersistenceUnitRootUrl
不能返回 null 否则 Hibernate 不会扫描类路径(Hibernate 5.2.8)。
我有点错了,这篇文章在这方面并没有过时,因为代码正在传递实体列表并且不使用包扫描。然而,对于自动实体扫描,必须实现getPersistenceUnitRootUrl
或getJarFileUrls
。后者播在***.com/a/42372648/48136【参考方案2】:
您也可以使用 PersistenceContext 或 Autowired 注释获取 EntityManager,但请注意它不是线程安全的。
@PersistenceContext
private EntityManager entityManager;
【讨论】:
【参考方案3】:我使用的 DataNucleus JPA 也有办法做到这一点in its docs。不需要 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);
【讨论】:
【参考方案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;
;
【讨论】:
这对我帮助很大,因为它帮助我避免了在某些测试用例中使用 arquillian 的开销!【参考方案5】:有没有办法在没有定义持久单元的情况下初始化
EntityManager
?
您应该在persistence.xml
部署描述符中定义至少一个持久性单元。
name 属性是必需的。其他属性和元素是可选的。 (JPA 规范)。所以这应该或多或少是你最小的您能否提供创建
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 提供者。因此,对于作为 JPA 提供者的 Hibernate,您的 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 SE 应用程序的可移植性,有必要明确列出包含在持久性单元(JPA 规范)中的托管持久性类通常,在 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);
【讨论】:
您好,我尝试了您的解决方案,但遇到了问题,请您检查我的问题:***.com/questions/3935394/… 但是...问题是如何创建一个JPA EntityManager 没有 persistence.xml。这个答案不错,不过还是用persistence.xml吧? 在 JavaEE 环境中,创建 EntityManagerFactory 是否由 EJB/JPA 管理?【参考方案6】:我能够使用 Hibernate 和 PostgreSQL 创建一个 EntityManager
,纯粹使用以下 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
【讨论】:
Hibernate 的不错替代品。【参考方案7】:是的,您可以在 @Configuration 类(或其等效的 spring config xml)中使用这样的 spring 而不使用任何 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
是什么对象?
它是一个简单的 java.util.Properties 对象以上是关于创建没有 persistence.xml 配置文件的 JPA EntityManager的主要内容,如果未能解决你的问题,请参考以下文章
JPA 对象关系映射总结---persistence.xml 文件配置要点