Java - Can Hibernate choose between two database configurations in persistence.xml? - java

I have a Java app running on Tomcat 7.0 with Hibernate managing the database.
I need to be able to switch the jdbc.url depending on a system environment variable (or possible another flag of sorts). Ultimately, I would like to be able to deploy a staging and production version of my webapp pointing to two different databases. However, at the moment, I have to physically change the jdbc.url value in persistence.xml and re-save it when switching between configurations.
My current persistence.xml file is:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="my_pu" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://my.rds.url.goes.here/mydatabase" />
<property name="javax.persistence.jdbc.user" value="myusername" />
<property name="javax.persistence.jdbc.password" value="mypassword" />
<property name="connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider"/>
</properties>
</persistence-unit>
</persistence>
I've read about using createEntityManagerFactory() as an option, but I can't find any clean examples of how to implement this. I'm certain this issue has been dealt with before, but I can't find a clean tutorial or advice.
How can I have my Hibernate switch database configurations without having to rewrite the persistence.xml file each time?

A couple of ways to do it, if you use spring or maven in your project, could be:
With maven as your build tool, you can replace properties during build time based on a maven profile - through filtering in the maven resource plugin
If you use spring in your project the PropertyPlaceholderConfigurer can inject the values for you. It can read the values as jvm parameters or from property files. These property files may be put in the tomcat/conf directory so each tomcat knows its own configuration, or you may build all possible properties, select them based on spring profile

Related

Why do we have to give database credentials in persistence.xml

We are using JPA 2.0 and we created the datasource in websphere and tried to access the database through the J2SE application. We are getting Invalid Username and password error. If we give the user name and password in persistence.xml it works fine.
Please anybody explain me why do we have to give the DB credentials in persistence.xml since we have the data source.
Note: Data Source was created successfully and the test was success.
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="Printer">
<jta-data-source>jdbc/TestDataSource</jta-data-source>
<properties>
<property name="openjpa.Optimistic" value="false" />
<property name="openjpa.LockManager" value="pessimistic" />
<property name="javax.persistence.jdbc.user" value="admin" />
<property name="javax.persistence.jdbc.password" value="admin#2" />
</properties>
</persistence-unit>
</persistence>
It seems that the datasource is not configured correctly in websphere. Test the database connection through the websphere console to verify the configuration.
A DataSource has 2 methods to get a Connection. It seems that your jpa implementation uses DataSource.getConnection(String username, String password) if you provide the credentials via properties.
The connection properties are intented to use in a Java SE environment. In JEE you should prefer the JNDI lookup. See section 8.2.1.9 of the JPA 2.0 specification.
You don't need to specify the credentials in your application. Just access your database via JNDI, specifying the name of the datasource you've created in the WS.
One way is to configure persistence unit using the pre-configured datasource (Please double check if it is configured correctly - the test feature is available in WS)
<persistence-unit name="default" transaction-type="JTA">
<provider>
oracle.toplink.essentials.PersistenceProvider
</provider>
<jta-data-source>
jdbc/MyDataSource
</jta-data-source>
<properties>
<property name="toplink.logging.level" value="INFO"/>
</properties>
</persistence-unit>
If the datasource is not configured on the application container side, you may set it up yourself on the application side. For example, you need a number of the applications each one has its own database connection config.
<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
<provider>
oracle.toplink.essentials.PersistenceProvider
</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="toplink.logging.level" value="INFO"/>
<property name="toplink.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
<property name="toplink.jdbc.url" value="jdbc:oracle:thin:#myhost:l521:MYSID"/>
<property name="toplink.jdbc.password" value="tiger"/>
<property name="toplink.jdbc.user" value="scott"/>
</properties>
</persistence-unit>
Your persistence.xml has the config for both ways. Remove the unnecessary code and try again.

Using derby built-in glassfish4 through EclipseLink

I have been trying to learn how to connect to the embedded database Apache Derby that comes out of the box with glassfish4. What do I have to set in the src/META-INF/persistence.xml in my project? Is it somehow preconfigured? If not, how can I change its settings - through glassfish console?
Thanks in advance for your help.
You need to edit the persistence.xml to add the persistence-provider, the classes you want to manage, and some configuration for your database, in case you do not use JTA, in your IDE, and package it with the app. You can generally enter the following in the persistence.xml:
<persistence-unit name="call_it_as_you_want" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>YourClass</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:derby://127.0.0.1:1527/yourDatabase;create=true" />
<property name="javax.persistence.jdbc.user" value="your_database_login" />
<property name="javax.persistence.jdbc.password" value="your_database_password" />
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
</properties>
</persistence-unit>
Before that, check if derby runs on port 1527 - i think it should. If you are going to use JPA with EJBs you can use JTA configuration - in this case persistence.xml will only need to declare the pool you will create from the admin console of Glassfish.

Location of the persistence.xml in a Java Client App

I am a newbie in Hibernate. In order to get the transaction by the EntityManager, I need to use EntityManager Factory. When I put this code block on my file:
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory("Comment");
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(obj);
transaction.commit();
I got this Exception:
javax.persistence.PersistenceException: No Persistence provider for EntityManager named Comment
Then I realized that I need to add a persistence.xml file:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<persistence-unit name="QuestionsComments" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>Comment</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="root"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/sogdb"/>
<property name="hibernate.max_fetch_depth" value="3"/>
</properties>
</persistence-unit>
</persistence>
Actually, The app I am using is not a Java on Server app (I have a Client app). Which means that there is no META-INF folder that will contain the persistence.xml file.
My Questions are:
1- Where I need to put the persistence.xml file?
2- Is the code below OK? Knowing that my table in the database is QuestionsComments and my class that will be related to it using Hibernate is Comment.
If you are using Eclipse, adding the JPA facet to your project allows Eclipse to take care of setting these things up for you. It will create the META-INF folder, and can generate a stub persistence.xml file in it. You don't have to be running the code on a server to have a META-INF folder in your jar file.
When you are creating the EntityManagerFactory the string argument should be the name of the persistence unit. I'd recommend using annotations in your entity class for specifying table name, id column, etc.
Edit: fixed link.
Answered clearly in this section of the Hibernate JPA Quick Start Guide. It goes in META-INF.
Check out the same guide just linked.
Personally I prefer the Hibernate-specific configuration hibernate.cfg.xml with annotations for mappings and Hibernate's SessionFactory for transaction access; I find it easier to wrap my head around -- although that's probably because I originally learned how to use Hibernate without knowing how to use JPA.

Is there a way to scan JPA entities not to declare persistent classes in a persistence.xml file?

I would like to take advantage of JPA #Entity annotations not to declare class entities a J2SE persistence.xml file. What I'd like to avoid :
<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.mycompany.entities.Class1</class>
<class>com.mycompany.entities.Class2</class>
<class>com.mycompany.entities.Class3</class>
</persistence-unit>
and here is what my actual persistence.xml look alike
<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<!-- Scan for annotated classes and Hibernate mapping XML files -->
<property name="hibernate.archive.autodetection" value="class, hbm" />
<property name="hibernate.cache.use_second_level_cache" value="false" />
<property name="hibernate.cache.use_query_cache" value="false" />
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
</properties>
</persistence-unit>
Is there a standard way to scan JPA entities in a persistence.xml file from within a JAR module?
Is there a unstandard Hibernate way to scan JPA entities in a persistence.xml file from within a JAR module?
-Make sure your entities and persistence.xml end up in the same classpath when you build your jar.
The entities cannot be scanned if they are sitting in another classpath. If you need to have them sitting in different classpaths, heres one trick I've seen to make it work: No autodetection of JPA Entities in maven-verify.
If you are unsure where things are ending, you can unzip the .jar file and peak. This is an unpacked persistence web project:
Notice my classes are down the com directory, and my persistence.xml is in the META-INF directory. Both are in the same 'classes' classpath, so autoscan will work.
-Set hibernate.archive.autodetection property.
<!-- Scan for annotated classes and Hibernate mapping XML files -->
<property name="hibernate.archive.autodetection" value="class, hbm" />
-Add false to the persistence-unit
<persistence-unit name=...>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
...
Hopefully one of those will work for you.

Migrate HAR hibernate archive to JBoss 7

I'm migrating an application packaged as a HAR hibernate archive from JBoss AS5 to AS7. I have a number of questions, and I know I have a number of hurdles I have to face in order to migrate my application successfully. I don't mind researching things on my own - but at this point I'm not quite sure what is possible, or the direction I should take and would appreciate any pointers or comments.
I know that JBoss AS7 does not support HAR hibernate archives - so I have to make some sort of changes in order to get this to work. My app requires hibernate3, which I include as a dependency. My HAR is structured like
HAR
|
|-com
| |-business classes
| |-*class files and *hbm.xml files
|
|-META-INF
|-hibernate.xml
My hibernate.xml file looks like
<hibernate-configuration xmlns="urn:jboss:hibernate-deployer:1.0">
<session-factory name="java:/hibernate/SessionFactory" bean="jboss.har:service=Hibernate">
<property name="datasourceName">java:/MySqlDS</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- <property name="sessionFactoryInterceptor">org.jboss.test.hibernate.SimpleInterceptor</property> -->
<!-- <property name="hbm2ddlAuto">create</property> -->
<depends>jboss:service=Naming</depends>
<depends>jboss:service=TransactionManager</depends>
</session-factory>
</hibernate-configuration>
We are using *hbm.xml files in our HAR to define entities, and not the newer style of hibernate annotations. A couple of questions I have are:
-is there a way I can just package my HAR as a JAR and use it inside of AS7 without having to go through the trouble of rewrite my business classes to use annotations to define entities instead of using *hbm.xml files?
-if not is there a guide somewhere about converting your code to use hibernate annotations and persistence.xml? I don't mind doing research but right now I'm not sure what I should be researching.
HAR archives do not exist in JBoss 7 anymore. In fact even the ServiceMBeanSupport does not exist anymore. One possibility is to use some mechanism to create the SessionFactory and inject it into the JNDI. Another possibility is to “use and not use” the new JPA api. By “use” I mean define Hibernate configuration in a persistence.xml file and use the mapping detection feature available. This would allow the plain renaming of the .har to a .jar with an added META-INF/persistence.xml file without the need to hardcode all the mappings and classes in a long list somewhere. By “not use” I mean to have the JPA initialized but use the old SessionFactory instead because there is no reason to change to the new API when the old one works quite well.
However, another problem is that JBoss 7 is bundled with Hibernate 4 and the migration might not be straightforward. However there is still a possibility to bundle a Hibernate as lower as 3.5 in your application. Here is the persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="X">
<description>X</description>
<jta-data-source>java:/XOracleDS</jta-data-source>
<properties>
<!-- This tells JBoss to use Hibernate 3 (as low as 3.5) bundled into the application -->
<property name="jboss.as.jpa.providerModule" value="hibernate3-bundled" />
<!--<property name="jboss.as.jpa.managed" value="false"/>-->
<!-- This will bind the session factory to JNDI as we require -->
<property name="hibernate.session_factory_name" value="java:/hibernate/XOracleSessionFactory"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<!-- This is one of the trickiest parts as Hibernate 3.5 does not has a RegionFactory and we must use the one from ehcache to bridge the gap -->
<property name="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.EhCacheRegionFactory"/>
<!-- very important to allow same names as in JBoss 4 -->
<property name="hibernate.cache.region_prefix" value=""/>
<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletonEhCacheProvider"/>
<!-- This will make use of JBoss managed transactions. The factory is already present in JNDI -->
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
<property name="hibernate.jdbc.batch_size" value="20"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.format_sql" value="false"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
</properties>
</persistence-unit>
</persistence>

Categories