在没有persistence.xml配置文件的情况下创建JPA EntityManager

jav*_*csw 74 jpa runtime entitymanager persistence.xml

有没有一种方法来初始化EntityManager没有定义的持久性单元?您能否提供创建实体管理器所需的所有属性?我需要EntityManager在运行时从用户的指定值创建.不能更新persistence.xml和重新编译.

关于如何做到这一点的任何想法都受到欢迎!

Art*_*ald 57

有没有一种方法来初始化EntityManager没有定义的持久性单元?

您应该在部署描述符中定义至少一个持久性单元persistence.xml.

你能提供所有必需的属性来创建Entitymanager吗?

  • name属性是必需的.其他属性和元素是可选的.(JPA规范).所以这应该或多或少是你的最小persistence.xml文件:
<persistence>
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
        SOME_PROPERTIES
    </persistence-unit>
</persistence>
Run Code Online (Sandbox Code Playgroud)

在Java EE环境中,jta-data-sourcenon-jta-data-source元素用于指定持久性提供程序要使用的JTA和/或非JTA数据源的全局JNDI名称.

因此,如果您的目标Application Server支持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>
Run Code Online (Sandbox Code Playgroud)

如果您的目标Application Server不支持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>
Run Code Online (Sandbox Code Playgroud)

如果您的数据源未绑定到全局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>
Run Code Online (Sandbox Code Playgroud)

交易类型属性

通常,在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);
Run Code Online (Sandbox Code Playgroud)

  • 但是...问题是如何在*没有* persistence.xml 的情况下创建 JPA EntityManager。这个答案很好,但它仍然使用 persistence.xml,对吗? (4认同)

Fra*_*ana 26

是的,您可以在@Configuration类(或其等效的spring config xml)中使用类似弹簧的任何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;
}
Run Code Online (Sandbox Code Playgroud)


Sle*_*led 18

我能够创建一个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();
}
Run Code Online (Sandbox Code Playgroud)

呼叫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();
Run Code Online (Sandbox Code Playgroud)

我的实体是这样的:

@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
}
Run Code Online (Sandbox Code Playgroud)

  • Hibernate 的不错选择。 (2认同)

Bri*_*ice 15

这是没有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();
Run Code Online (Sandbox Code Playgroud)

臭名昭着 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;
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

  • 这对我帮助很大,因为它帮助我避免在一些测试用例中使用arquillian的开销! (3认同)

Vla*_*cea 5

使用普通的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()
);
Run Code Online (Sandbox Code Playgroud)

PersistenceUnitInfo由Spring特定实现MutablePersistenceUnitInfo类.

查看这篇文章,了解如何使用Hibernate实现这一目标.

  • 我有点错了,这篇文章在这方面并没有过时,因为代码正在传递实体列表并且不使用包扫描。然而,对于自动实体扫描,有必要实现“getPersistenceUnitRootUrl”或“getJarFileUrls”。后者播种于http://stackoverflow.com/a/42372648/48136 (2认同)