覆盖JPA持久性单元

时间:2017-03-07 12:50:11

标签: java jpa

我的jar文件中有一个空的persistenceUnit:

 <persistence-unit transaction-type="JTA" name="base1">
    </persistence-unit>

    <persistence-unit transaction-type="JTA" name="base2">
    </persistence-unit>

我的想法是用我的主项目中的属性和类替换空persistenceUnit一个完整的persistenceUnit,如下所示:

<persistence-unit name="base1" transaction-type="JTA">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <jta-data-source>java:jboss/datasources/myDS</jta-data-source>
        <class>br.com.myproject.MyClass</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <shared-cache-mode>NONE</shared-cache-mode>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="none" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="false" />
            <property name="hibernate.cache.use_second_level_cache"
                      value="false" />
        </properties>
    </persistence-unit>

但是当我尝试启动服务器时出现以下错误:

 Caused by: org.jboss.as.server.deployment.DeploymentUnitProcessingException: WFLYJPA0038: Falha ao adicionar o serviço da unidade de persistência para base1
    Caused by: org.jboss.msc.service.DuplicateServiceException: Service jboss.persistenceunit.myproject#base1.__FIRST_PHASE__ is already registered"}}

有没有办法覆盖persistenceUnit?

3 个答案:

答案 0 :(得分:0)

如果您确实需要动态覆盖persistence.xml,最好在构建期间完成。

我的个人警告:这对我来说听起来像配置 - 我宁愿建议在这里使用容器管理的JNDI方法。

但无论如何: 使用2个maven配置文件。 如果激活profile1,则会在正确的位置添加来自profile1的persistence.xml。如果你从profile2激活profile2 persistence.xml将被采取。

因此使用copy-resources-mojo作为maven。 https://maven.apache.org/plugins/maven-resources-plugin/examples/copy-resources.html

如果只是参数值发生变化,而不是整个结构, 那么你也可以在maven-processes期间“过滤”并替换字符串 那么你将在配置文件中定义属性。 https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html

您还可以将基本persistence.xml作为默认文件添加到项目中。因此,如果没有激活maven-profile,将使用这个。 (即使可能发生,如果未正确配置数据资源,应用程序也无法按预期工作)

答案 1 :(得分:0)

Spring提供了一个接口JpaVendorAdapter,它允许在应用程序启动期间通过Spring Java配置或XML配置插入任何JPA供应商特定的配置。

您可以使用LocalContainerEntityManagerFactoryBean和JpaVendorAdapter的任何实现类创建EntityManagerFactory实例,例如HibernateJpaVendorAdapter,EclipseLinkJpaVendorAdapter或OpenJpaVendorAdapter。

我相信如果你的应用程序使用Spring,你甚至不需要在persistence.xml中定义空的持久性单元。

以下是有关如何使用Spring Java config创建EntityManagerFactory的示例:

    @Inject 
    private DataSource base1DataSource;

    @Inject 
    private DataSource base2DataSource;

    @Bean
    public EntityManagerFactory base1EntityManagerFactory()
            throws IOException, NamingException {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();

        LocalContainerEntityManagerFactoryBean containerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        containerEntityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
        containerEntityManagerFactoryBean.setPackagesToScan("YOUR_PACKAGE_NAMES");
        containerEntityManagerFactoryBean.setJtaDataSource(base1DataSource);
        containerEntityManagerFactoryBean.setJpaProperties(loadBase1JpaProperties());
        containerEntityManagerFactoryBean.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
        containerEntityManagerFactoryBean.setPersistenceUnitName("base1");
        containerEntityManagerFactoryBean.afterPropertiesSet();

        return containerEntityManagerFactoryBean.getObject();
    }

    @Bean
    public EntityManagerFactory base2EntityManagerFactory()
            throws IOException, NamingException {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();

        LocalContainerEntityManagerFactoryBean containerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        containerEntityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
        containerEntityManagerFactoryBean.setPackagesToScan("YOUR_PACKAGE_NAMES");
        containerEntityManagerFactoryBean.setJtaDataSource(base2DataSource);
        containerEntityManagerFactoryBean.setJpaProperties(loadBase2JpaProperties());
        containerEntityManagerFactoryBean.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
        containerEntityManagerFactoryBean.setPersistenceUnitName("base2");
        containerEntityManagerFactoryBean.afterPropertiesSet();

        return containerEntityManagerFactoryBean.getObject();
    }

    @Bean
    public Properties loadBase1JpaProperties() throws IOException {
        ClassPathResource resource = new ClassPathResource("base1-persistence.properties");

        return PropertiesLoaderUtils.loadProperties(resource);
    }

    @Bean
    public Properties loadBase2JpaProperties() throws IOException {
        ClassPathResource resource = new ClassPathResource("base2-persistence.properties");

        return PropertiesLoaderUtils.loadProperties(resource);
    }

有关可以覆盖到persistence.xml的内容的其他信息,请参阅以下URL: http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.html

答案 2 :(得分:0)

我假设您要在超类中声明持久单元,并且希望在显式项目中定义持久单元。如果是,你可以使用这样的JNDI approch:

<persistence-unit name="MyPersistenceUnit"
    transaction-type="JTA">

    <jta-data-source>java:/myDS</jta-data-source>

    <mapping-file>META-INF/orm.xml</mapping-file>


    <jar-file>Persistence.jar</jar-file>

    <properties>

        <property name="jboss.entity.manager.jndi.name" value="java:app/applicationEntitymanager"/>  
        <!-- Properties for Hibernate -->
        <property name="hibernate.hbm2ddl.auto" value="update" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
        <property name="hibernate.show_sql" value="false" />
    </properties>

</persistence-unit>

另一方面,您可以通过以下方式访问Entitymanager:

@Resource(mappedName = "java:app/applicationEntitymanager")
protected EntityManager em;