如何通过 database.properties 文件使数据库配置可配置的 persistence.xml 文件

Posted

技术标签:

【中文标题】如何通过 database.properties 文件使数据库配置可配置的 persistence.xml 文件【英文标题】:how to make database configuration configurable of persistance.xml file through database.properties file 【发布时间】:2016-02-28 17:29:49 【问题描述】:

我想确认查询“有什么方法可以通过persistance.xml 中的database.properties 进行数据库配置配置”。以下是可能的吗?

我的以下配置工作得很好,

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="spring-data-jpa-krishna" transaction-type="RESOURCE_LOCAL">
        <class>net.javabeat.springdata.model.Address</class>
        <class>net.javabeat.springdata.model.Employee</class>

        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/test" />
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="javax.persistence.jdbc.user" value="root" />
            <property name="javax.persistence.jdbc.password" value="root" />

            <property name="hibernate.show_sql" value="true" />
            <property name="eclipselink.logging.level" value="FINE" />
            <property name="eclipselink.ddl-generation" value="create-tables" />
        </properties>
    </persistence-unit>
</persistence>

但是我有很多环境可以部署 Dev、QA、UAT、SAT、SystemTest 等应用程序代码,所以我想进行如下配置 数据库属性:

mysql.jdbc.driver.class=com.mysql.jdbc.Driver
mysql.jdbc.url=jdbc:mysql://localhost:3306/test
mysql.jdbc.username=root
mysql.jdbc.password=root
hibernate.show_sql=true
eclipselink.logging.level=FINE
eclipselink.ddl-generation=create-tables

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="spring-data-jpa-krishna" transaction-type="RESOURCE_LOCAL">
        <class>net.javabeat.springdata.model.Address</class>
        <class>net.javabeat.springdata.model.Employee</class>

        <properties>
            <property name="javax.persistence.jdbc.url" value="$mysql.jdbc.url" />
            <property name="javax.persistence.jdbc.driver" value="$mysql.jdbc.driver.class" />
            <property name="javax.persistence.jdbc.user" value="$mysql.jdbc.username" />
            <property name="javax.persistence.jdbc.password" value="$mysql.jdbc.password" />

            <property name="hibernate.show_sql" value="$hibernate.show_sql" />
            <property name="eclipselink.logging.level" value="$eclipselink.logging.level" />
            <property name="eclipselink.ddl-generation" value="eclipselink.ddl-generation" />
        </properties>
    </persistence-unit>
</persistence>

这将帮助我解决开销问题。但我想知道persistece.xml 将如何加载database.properties 以正确获取占位符

这个How to externalize properties from JPAs persistence.xml? 链接是通过JNDI 完成的,但我只是想通过database.properties 文件完成。

编辑-1: 是的,我使用的是 spring-Context.xml 文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd 
        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd 
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- For consider the using of annotations foe defining Spring Bean -->
    <context:annotation-config />

    <!-- For defining Spring Bean -->
    <context:component-scan base-package="net.javabeat.springdata.beans" />

    <!-- For bootstrapping the Spring Repository -->
    <jpa:repositories base-package="net.javabeat.springdata.repository" />

    <!-- Necessary to get the entity manager injected into the factory bean -->
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <bean id="registrationBean" class="net.javabeat.springdata.beans.RegistrationBean" />


    <!-- =======  WAY-1    ========= -->
    <!-- ===== Define EclipseLink JPA Vendor Adapter ===== -->
    <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
        <property name="databasePlatform" value="org.eclipse.persistence.platform.database.MySQLPlatform" />
        <property name="generateDdl" value="false" />
        <property name="showSql" value="true" />
    </bean>

    <!-- Entity Manager Factory -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        =========== Read persistent.xml file from here  ===========
        <property name="persistenceUnitName" value="spring-data-jpa-krishna" />
        <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
        <!-- spring based scanning for entity classes-->
        <property name="packagesToScan" value="net.javabeat.springdata.*" />
    </bean> 

    <!-- Transaction Manager -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <!-- Enable Transactional Manner -->
    <tx:annotation-driven transaction-manager="transactionManager" />

</beans>

Edit-1:我现在看到以下错误:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private net.javabeat.springdata.repository.EmployeeRepository net.javabeat.springdata.beans.RegistrationBean.employeeRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'employeeRepository': Cannot create inner bean '(inner bean)#5d3c9c43' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5d3c9c43': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [SpringContext.xml]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: PersistenceProvider [org.eclipse.persistence.jpa.PersistenceProvider@6201c010] did not return an EntityManagerFactory for name 'spring-data-jpa-krishna'
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
    ... 13 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'employeeRepository': Cannot create inner bean '(inner bean)#5d3c9c43' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5d3c9c43': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [SpringContext.xml]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: PersistenceProvider [org.eclipse.persistence.jpa.PersistenceProvider@6201c010] did not return an EntityManagerFactory for name 'spring-data-jpa-krishna'
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:313)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:129)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1475)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1220)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1120)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1044)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533)
    ... 15 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5d3c9c43': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [SpringContext.xml]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: PersistenceProvider [org.eclipse.persistence.jpa.PersistenceProvider@6201c010] did not return an EntityManagerFactory for name 'spring-data-jpa-krishna'
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:634)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:444)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1117)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1012)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:299)
    ... 28 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [SpringContext.xml]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: PersistenceProvider [org.eclipse.persistence.jpa.PersistenceProvider@6201c010] did not return an EntityManagerFactory for name 'spring-data-jpa-krishna'
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1572)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
    ... 36 more
Caused by: java.lang.IllegalStateException: PersistenceProvider [org.eclipse.persistence.jpa.PersistenceProvider@6201c010] did not return an EntityManagerFactory for name 'spring-data-jpa-krishna'
    at org.springframework.orm.jpa.LocalEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalEntityManagerFactoryBean.java:90)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1631)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1568)
    ... 43 more

我对 pom.xml 文件进行了更改:

<build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.1</version>
                    <configuration>
                        <source>$java.version</source>
                        <target>$java.version</target>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
        <!-- <filters>
            <filter>database.properties</filter>    
        </filters> -->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
    </build>

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="spring-data-jpa-krishna" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>net.javabeat.springdata.model.Address</class>
        <class>net.javabeat.springdata.model.Employee</class>

        <!-- http://docs.oracle.com/cd/E16439_01/doc.1013/e13981/cfgdepds005.htm -->
        <properties>        
            <property name="javax.persistence.jdbc.url" value="$jdbc.mysql.url" />
            <property name="javax.persistence.jdbc.driver" value="$jdbc.mysql.driver.class" />
            <property name="javax.persistence.jdbc.user" value="$jdbc.mysql.username" />
            <property name="javax.persistence.jdbc.password" value="$jdbc.mysql.password" />

            <property name="eclipselink.logging.level" value="FINE" />
            <property name="eclipselink.ddl-generation" value="create-tables" />
        </properties>
    </persistence-unit>
</persistence>

【问题讨论】:

如果您使用 Spring,您可以选择使用persistence.xml 并从database.properties 获取属性来配置LocalContainerEntityManagerFactoryBean 另外,您同时使用了Eclipse LinkHibernate 特定选项,为什么? Ali - 是的,我正在使用 spring,请参阅下面的更新和 spring-Context.xml 文件。可能是 Hibernate 特定的选项可能不相关且未被使用,以上配置就是证明 你误将我心爱的persistence.xml复制了两次。 【参考方案1】:

当您使用 Spring 时,您可以选择根本不使用 persistence.xml,并通过名为 LocalContainerEntityManagerFactoryBeanFactoryBean 配置 EntityManagerFactory。这个answer 可以让您了解如何配置LocalContainerEntityManagerFactoryBean

如果您坚持使用persistence.xml,您可以在persistence.xml 中添加$... 占位符,并使用Maven 的资源过滤 来填充实际值。使用这种方法,您应该将 Property Values 定义为 Maven 属性,并且您不需要单独的 database.properties。在这种方法中,您应该将属性添加为 maven 属性,如下所示:

<properties>
    <mysql.jdbc.driver.class>com.mysql.jdbc.Driver</<mysql.jdbc.driver.class>
    <mysql.jdbc.url>jdbc:mysql://localhost:3306/test</mysql.jdbc.url>
    <mysql.jdbc.username>root</mysql.jdbc.username>
    <mysql.jdbc.password>root</mysql.jdbc.password>
    <hibernate.show_sql>true</hibernate.show_sql>

    <!-- You've got to be kidding me! -->
    <eclipselink.logging.level>FINE</eclipselink.logging.level>
    <eclipselink.ddl-generation>create-tables</eclipselink.ddl-generation>
</properties>

然后将这些添加到pom.xml 中的构建部分:

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
        </resource>
    </resources>
</build>

src/main/resources 中资源中具有 $... 语法的每个占位符都将替换为其实际值,即在 pom.xmlproperties 部分中定义的值。

【讨论】:

阿里 - 非常感谢你,请查看我的更新 Edit-1 您应该将这些 properties 添加到您的 pom.xml 你能看一下我来自github.com/test512/spring-data-jpa-krishna的代码吗?它不适合我 我可以修复您的项目,但 imo 最好使用 Spring Boot。它将代表您自动配置大多数这些配置。看看spring boot,相信我,值得! 同意,谢谢,我很快就会全力以赴。目前,请修复此问题。

以上是关于如何通过 database.properties 文件使数据库配置可配置的 persistence.xml 文件的主要内容,如果未能解决你的问题,请参考以下文章

尝试部署服务器时找不到 database.properties

java连接数据库以及连接参数格式

spring boot datasource

SSM框架的搭建

SSM框架基础配置文件

您如何将 UTL_FILE.FILE_TYPE 作为输出参数