My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
PersistenceUnitSetup  

The most critical point for having two (or more) database connections on the same Spring JPA application is to setup correctly persistence units.

In this article I try to explain it in details. Please checkout the source code for a complete working solution: svn checkout http://gwt-spring-jpa-lucene.googlecode.com/svn/com.intre.open.gwtjpa

This is a draft

Toc

Important files

Plase note: the path may differ if you change the package names, this is a demo project! I've called the first database first and the second second. Therefore some configuration files are replicated with different configurations. Please read carefully the first configuration files (.first.) and replicate them for all connections you need.

  • war/WEB-INF/web.xml: spring configuration loader and GWT-RPC service definition
  • war/WEB-INF/applicationContext.xml: persistence unit manager locations
  • src/com/intre/open/gwtjpa/data/first/resources/applicationContext.data.first.xml: gilead, hibernate and DAO configuration for the first connection
  • src/com/intre/open/gwtjpa/data/first/resources/datasource.data.first.xml: datasource configuration for the first connection
  • src/com/intre/open/gwtjpa/data/first/resources/persistence.data.first.xml: persistence unit manager for first connection
  • src/com/intre/open/gwtjpa/data/first/resources/applicationContext.data.second.xml: second connection DAO
  • src/com/intre/open/gwtjpa/data/first/resources/datasource.data.second.xml: second connection datasource
  • src/com/intre/open/gwtjpa/data/first/resources/persistence.data.second.xml: second connection persistence unit

Declare the persistence unit manager

This is the most important configuration to do in order to have more connection at the same time. In file war/WEB-INF/applicationContext.xml you define a DefaultPersistenceUnitManager that acts as lookup for all persistence units in your project.

<bean id="pum"
		class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
		<property name="persistenceXmlLocations">
			<list>
				<value>classpath:/com/intre/open/gwtjpa/data/first/resources/**/persistence.data.first.xml
				</value>
				<value>classpath:/com/intre/open/gwtjpa/data/second/resources/**/persistence.data.second.xml
				</value>
			</list>
		</property>
		<!--  comment dataSourceLooup to use jndi -->
		<property name="dataSourceLookup">
			<bean
				class="org.springframework.jdbc.datasource.lookup.BeanFactoryDataSourceLookup" />
		</property>
</bean>

The pum defines the persistenceXmlLocations that includes all persistence.xml files. Inside the persistence.xml you define the persistece unit.

<persistence-unit name="data_first_pu" transaction-type="RESOURCE_LOCAL">

	<non-jta-data-source>dataFirstDataSource</non-jta-data-source>
	
	<class>com.intre.open.gwtjpa.data.first.domain.Person</class>
	
	<properties>
		<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
		<property name="hibernate.archive.autodetection" value="false"/>
		<property name="hibernate.transaction.auto_close_session" value="false"/>
           
		<property name="hibernate.search.default.directory_provider" value="org.hibernate.search.store.FSDirectoryProvider"/>
		<property name="hibernate.search.default.indexBase" value="lucene-first"/>
		<property name="hibernate.search.default.locking_strategy" value="none"/>
	</properties>

</persistence-unit>

The name of the persistence unit, in the example data_first_pu is annotated in the DAO

package com.intre.open.gwtjpa.data.first.server.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.log4j.Logger;

import com.intre.open.gwtjpa.data.first.domain.Person;


public class DataFirstDAO {

	static final Logger logger = Logger.getLogger(DataFirstDAO.class);
	public final static String NAME = "dataFirstDAO";
	
	@PersistenceContext(unitName="data_first_pu")
	protected EntityManager entityManager;
        .
        .
        .
}

To perform CRUD operations you need transactions. Transactions are managed by Spring/JPA with the ServiceSpring class

package com.intre.open.gwtjpa.data.first.server.spring;

import java.util.List;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.intre.open.gwtjpa.data.first.domain.Person;
import com.intre.open.gwtjpa.data.first.server.dao.DataFirstDAO;

@Transactional(value = "first", propagation = Propagation.REQUIRED)
public class DataFirstServiceSpring {

	public static final String FIRST_SERVICE_NAME = "dataFirstService";
	private static final long serialVersionUID = -707833153923495944L;
	
	private DataFirstDAO dao;

	public void setDao(DataFirstDAO dao) {
		this.dao = dao;
	}

	public DataFirstDAO getDao() {
		return this.dao;
	}

	@Transactional(value = "first", propagation = Propagation.SUPPORTS)
	public List<Person> loadAll() {
		return getDao().loadAll();
	}
	
}

The transaction is annotated with @Transactional(value = "first" ...) this allows to have two transaction on two different connection. The value first is defined in applicationContext.data.xml by the JpaTransactionManager

        <bean id="dataFirstTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="dataFirstEntityManagerFactory" />
		<qualifier value="first" />
		<property name="jpaDialect">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
		</property>
	</bean>

where dataFirstEntityManagerFactory links the Persistence Unit Manager (pum) with the Persistence Unit of your connection (data_first_pu)

       <bean id="dataFirstEntityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitManager" ref="pum" />
		<property name="persistenceUnitName" value="data_first_pu" />
		<property name="jpaVendorAdapter" ref="dataFirstJpaVendor" />
		<property name="loadTimeWeaver">
			<bean
				class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
		</property>
		<property name="jpaDialect">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect">
			</bean>
		</property>
	</bean>

More details about Gilead and GWT will follow in next pages.

Comment by arzu...@gmail.com, May 3, 2011

How did you get past org.springframework.beans.factory.NoSuchBeanDefinitionException?: No unique bean of type [javax.persistence.EntityManagerFactory?] is defined: expected single bean but found 2??

You have two beans of type LocalContainerEntityManagerFactoryBean? which would result in this exception.

Comment by project member giulio.r...@gmail.com, May 3, 2011

Hi Arzu, the pum and the annotation in the DAO do the trik. Have you checked the source code at http://gwt-spring-jpa-lucene.googlecode.com/svn/com.intre.open.gwtjp? in the eclipse project you can find the full example with two datasources. If you can please share with me your source code, I may help you to find out the problem

Comment by techgur...@gmail.com, Jun 4, 2011

Hi I am trying your multiple PU solution to work with Spring + JPA + Hibernate in JBoss, but somehow I am getting javax....PersitenceException?. can not create the emf, PU not found. Would you please explain why this would happen?

Also like in your example you have definded datasource in spring context and you are also providing the non-jta-datasource in persitence.xml. I did not understand this piece, which one will be used by spring when it create PUInfo instance?

Comment by project member giulio.r...@gmail.com, Jun 5, 2011

Hi techguru07, the src code has been tested under Tomcat6. I haven't tested in in JBoss :( The non-jta-datasource is referenced by persistence.xml but defined in datasource.data.xml.

Please check this configuration: http://code.google.com/p/gwt-spring-jpa-lucene/source/browse/com.intre.open.gwtjpa/trunk/src/com/intre/open/gwtjpa/data/first/resources/datasource.data.first.xml and http://code.google.com/p/gwt-spring-jpa-lucene/source/browse/com.intre.open.gwtjpa/trunk/src/com/intre/open/gwtjpa/data/first/resources/datasource.data.first.xml

The jpa entity manager is configured here http://code.google.com/p/gwt-spring-jpa-lucene/source/browse/com.intre.open.gwtjpa/trunk/src/com/intre/open/gwtjpa/data/first/resources/applicationContext.data.first.xml

and you need the pum lookup http://code.google.com/p/gwt-spring-jpa-lucene/source/browse/com.intre.open.gwtjpa/trunk/war/WEB-INF/applicationContext.xml

remember that in Tomcat you have to load the spring configuration http://code.google.com/p/gwt-spring-jpa-lucene/source/browse/com.intre.open.gwtjpa/trunk/war/WEB-INF/web.xml with the contextConfigLocation and org.springframework.web.context.ContextLoaderListener?.

For JBoss please attach more deatails in your comment(JBoss version also) that I try to figure out the problem :)

Comment by techgur...@gmail.com, Jun 7, 2011

Thanks for the reply, i really appreciate it. But as per your configuration , you have used "DriverManagerDataSource?" which is not recommended in production quality code as it does not use the connection pool. Also if this kind of app is deployed in J2EE container then it is better to use jndi datasource. So those changes I have to make so that spring look for jndi datasource, and i think that is causing an issue as JBoss expose the jndi datasource as for eg "java:myDatasource" and in spring we have to use "org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup?" so that spring can lookup for datasource exposed by J2EE container. Now when we use this bean, by default it look for datasource in "java:comp/env/myDatasource" which is not how jboss expose it. So i would appreciate if you shed some light on this. Also if you can add some more documenation about how each configuration is used by spring to create emf and em would also be great and people will really appreciate it as spring docs are not having enough information about it.

Thanks

Comment by techgur...@gmail.com, Jun 7, 2011

Also to add to the above note, I am not using GWT,lucene so I have to remove those specific config.

Comment by techgur...@gmail.com, Jun 7, 2011

jboss version i am using is 5.0 and 5.1

Comment by project member giulio.r...@gmail.com, Jun 7, 2011

@techguru07, what you are writing is true, the configuration should be leveraged to a connection pool with jndi datasource. In the applicationContext there is a comment about that.

Actually you have to comment in war/WEB-INF/applicationContext.xml bean pum this property

<!--<property name="dataSourceLookup">

<bean class="org.springframework.jdbc.datasource.lookup.BeanFactoryDataSourceLookup" />
</property>-->

and in the datasource.xml use your jndi name

<bean id="surveyDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">

<property name="jndiName" value="java:comp/env/myDatasource" />
</bean>

Please let me know it this for for you :)

Comment by techgur...@gmail.com, Jun 8, 2011

Thanks Giulio, I am trying this config but I am keep getting transaction related exception as below

 Caused by: javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: -3f57f2f6:ef6e:4df018bf:63 status: ActionStatus.ABORT_ONLY >

I am getting the db connection exposed by jboss server

Comment by techgur...@gmail.com, Jun 8, 2011

And I am using qualifier in my @Transaction annotation too

Comment by project member giulio.r...@gmail.com, Jun 9, 2011

It seems that Transaction is not opened. Usually happen when the EntityManager? is not correctly configured in DAO.

Can you copy here the method of SpringService? that starts the transaction with @Transaction?

Has the DAO {{{@PersistenceContext?(unitName="data_first_pu")

protected EntityManager? entityManager;}}}
configured?

Does the SQL query/command is executed by DAO called by SpringService??

Remember that in applicationCotext you need to add dao to springservice

<bean id="dataFirstDAO"
                class="com.intre.open.gwtjpa.data.first.server.dao.DataFirstDAO" />
<bean id="dataFirstService"
                class="com.intre.open.gwtjpa.data.first.server.spring.DataFirstServiceSpring">
     <property name="dao" ref="dataFirstDAO" /
</bean>
Comment by techgur...@gmail.com, Jun 9, 2011

Yes, my base dao class is annotated with @PersistenceContext??(unitName="pu1") and I have my dao and service beans also declared as spring bean. But I believe the problem is we are using jboss provided datasource so, dont know we also have to change the transation manager setting as we suppose to use jboss provided transation.

Comment by project member giulio.r...@gmail.com, Jun 9, 2011

I see, transaction management should be delegated to Spring, the datasource should just create connection session to db. Can you try to disable transaction management in jboss datasource? (I'm not familiar with JBoss...)

Comment by techgur...@gmail.com, Jun 9, 2011

No we cannot disable the transaction in jboss as if you are deploying an app in jboss and using server provided datasource then it is better to use server provided transaction. That is something I read on jboss docs.

Comment by techgur...@gmail.com, Jun 9, 2011

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/session-configuration.html

Comment by project member giulio.r...@gmail.com, Jun 9, 2011
Comment by techgur...@gmail.com, Jun 9, 2011

Up to some extent , I am doing the same thing and still got the transaction related exception. But let me go deep in to it and see whether its gonna fix this issue or not. Thanks for continuous update.

Comment by techgur...@gmail.com, Jun 9, 2011

Another problem is the link you sent earlier had another link ("Eric Soomsam blog") where it explains about this scenario is not longer available.

Comment by project member giulio.r...@gmail.com, Jun 9, 2011

Ok! Please let me know if you resolve the transaction problem :) Meanwhile I'll try to replicate your problem. I'd like to add a paragraph to this page about Jboss.

Comment by project member giulio.r...@gmail.com, Jun 16, 2011

@techguru07 have you find out the solution? googling your problem someone suggest to check exceptions in your code - http://thejavablog.wordpress.com/2010/04/05/transaction-is-not-active-txtransactionimple-ac-basicaction. May be that somewhere there is an exception that ends your transaction. Transactions are not explicit started but are started entering in the scope Spring Service Object methods, when you go out form that scope the transaction is closed.

Comment by brd...@gmail.com, Jun 28, 2011

I have gone through all your three tutorial , its excellent.. I am involved in migrating from struts/Java/Jobss application to GWT/spring/hibernate/Jboss and I want to use your dynamic data source using spring and hibernate. How can I use your tutorial in my application . Let me describe my requirement. When user login using his email id , from “masterdatabase” you will get companyid. Depend on company ID , I need to access datasoruce “companyid_DS” . I have tried using hard coded and its work, but how can I scale this approach in enterprise application. Any pointer appreciated.

I can share sample code I have written ( by hard code specifying company1, company2…….xml and data source ). Thanks in advance.

JP

Comment by project member giulio.r...@gmail.com, Jun 29, 2011

Hi JP, I'm happy that this tutorial helped in your migration :) A question: the name and the number of companies is known or change at runtime?

In the first case it's simple using a PropertyPlaceholderConfigurer? with $(companyid_DS). When you get the company id you can implement a org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource? that routes to the correct ds -http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/

In the second case the problem is more complicated because you have to change the whole spring configuration implementing your dynamic datasource lookup mechanism.

May be during holidays I can investigate more on AbstractRoutingDataSource? and write a wiki page about this configuration. Meanwhile if this is your case let us know if AbstractRoutingDataSource? solved your problem. Ciao Giulio

Comment by brd...@gmail.com, Jun 29, 2011

Thanks for prompt reply. and waiting for further update from you. Let me describe my scenario of accessing two databases. We maintain master database , which hold email id, User id, companyid Once user try to login to our application , it will validate again master database , if his/her email is in database , it will get company id information. After getting company id , we have to access "companyid_ds" and establish session to work on application. For example test1@email.com,test10@email.com , test22@email.com users belong to company1.

test111a@email.com,myemail2@email.com belong to company2.. like that we have define in our master database.

To answer your question, Yes we have fix set of companies define before user access database ( we have around 30 companies and 200 users define in master database ). Thanks

JP

Comment by project member giulio.r...@gmail.com, Jul 4, 2011

Hi JP, in your scenario the dynamic-datasource-routing is the correct approach. Let me know if do you need help in implementing the routing class. Giulio


Sign in to add a comment
Powered by Google Project Hosting