-->

Hibernate JTA : Read DB connection parameters per

2019-04-24 10:06发布

问题:

I am writing a javaEE application, using hibernate. The application will be running on multiple environments (dev, qa, prod etc.) & will have separate dbs's associated with each of them. I would like to set the hibernate properties like jdbc-url, username , password etc. separately for each of these environments.

My current persistence.xml looks like :

    <persistence-unit name="PU" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <validation-mode>CALLBACK</validation-mode>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect" />
            <property name="hibernate.hbm2ddl.auto" value="validate" />

            <property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
            <property name="hibernate.event.merge.entity_copy_observer" value="allow"/>

            <property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver"/>
            <property name="hibernate.connection.url" value="jdbc:oracle:thin:@host/schema"/>

            <property name="hibernate.connection.username" value="abc"/>
            <property name="hibernate.connection.password" value="***"/>    

        </properties>
    </persistence-unit>

I am using the persistence unit as follows in my java code:

@PersistenceContext(unitName = "PU")
private EntityManager em; 

Is there a way that I can inject the hibernate properties, which are stored in separate properties files, into EntityManager for different environments ?

Please note that I am using JTA and hence cannot use EntityManagerFactory. Also I am not & do not want to use spring.

回答1:

It is really a BAAAAAAD idea to include environment-specific information in your application WAR/EAR bundle (either by including multiple configs, or by creating different bundles for different environment). Different database, for example, should be maintained in the container.

In your case, your persistence.xml should look like:

<persistence>
   <persistence-unit name="PU">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <jta-data-source>jdbc/fooAppDs</jta-data-source>
      <properties>
         ... ...
      </properties>
   </persistence-unit>
</persistence>

and of course you should have corresponding resource-ref for jdbc/fooAppDs.

By doing so, you can deploy your application in any environment. You just need to create correct datasource in your container and assign it to jdbc/fooAppDs.


Another approach I believe will work, though I will not recommend, is by creating hibernate.cfg.xml in classpath. You may want to have a local file system location and add that in classpath, instead of putting the file in your JAR/WAR/EAR.



回答2:

Since you do not want to use external library such as Spring to bootstrap your persistence units, why not use your build system to do this. If you are using maven, you can use mix of maven filtering and profiles to filter based on properties file or if you are using any other build tool, you can add a task (or equivalent) to copy file contents from different files to actual file depending upon some external system/environmental variable.



回答3:

We used maintain property files for each environment such as DEV,QA,PROD,UAT etc in different files and copy one of them during build.

Ant build

<property environment="env" /> 
                <!-- ***** COMMAND LINE ARGUMENTS DEMOED HERE -->
                <property name="build_type" value= "${env.build_type}"/>

<copy todir="deploy">
    <fileset dir="src_dir"/>
    <globmapper from=${env.build_type}".persistence.xml" to="persistence.xml"/>
 </copy>

Run build like this

ant -Denv.build_type=PROD

This will copy PROD.persistence.xml to persistence.xml

ant -Denv.build_type=DEV

This will copy DEV.persistence.xml to persistence.xml



回答4:

With Spring Profile you could initiate entity manager beans depending upon the active profile that will refer to the persistence.xml like dev-persistence.xml, test-persisitence.xml, prod-persistence.xml of your environment. And you can set Active profile using web.xml. Mostly the web.xml won't change that much so you can keep the web.xml in your repository with the spring profile active property set for that enviornment.



回答5:

you can configure your spring-config.xml file as following

  1. MYSQL
<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/kaya_db" />
    <property name="username" value="root" />
    <property name="password" value="nxtlife" />
</bean>
<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"></property>
    <property name="packagesToScan" value="com.nxtlife.model" />
    <property name="hibernateProperties">

        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
        </props>
    </property>
</bean>
<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager"
    p:sessionFactory-ref="sessionFactory">
</bean>

2.Similar for other database like oracle,postgre with different name of datasource,sessionfactory and transactionmanager. 3. Finally you can get object of session factory using following sessionfactory name

@Modifier("sessionfactoryname")
@Autowired
private SessionFactory obj;

similar for different database