Announcement Announcement Module
Collapse
No announcement yet.
Spring 3 + Hibernate 3 with Multiple Datasources - Best Practice Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring 3 + Hibernate 3 with Multiple Datasources - Best Practice

    Ok, folks...I'm really at a loss here. To be sure I'm an amateur at transaction management, interceptors, etc but this is bordering on ridiculous and I've not found a post that successfully addressed my issue.

    I have a small application which needs to pull data from one table in one database and another identical table in another database (it's a queuing table). With 2 databases, I obviously have 2 datasources, and 2 sessionFactories. I am using Spring 3.0.5 and Hibernate 3.6, both with annotations.

    I started with a single datasource and a single DAO for accessing the table in one of the databases. This was working perfectly with annotations and the default transactionManager. Now I want to take the code and make it work with the other database as well. So here are my questions and what I've experienced so far:

    1) Do I need separate TransactionManagers? It would seem so and I have done this, giving each a qualifier value that is referred to in my Service -or- DAO class(es) using @Transactional("qualifier") notation. Is this proper or is there a better way?

    2) What about interceptors? Do I need separate interceptors if I have two TransactionManagers? With the 'qualified' notation above, shouldn't Spring be able to locate the proper TransactionManager without me manually creating interceptors? If not, is there a good example out there of how to create separate interceptors and direct specific classes that use them?

    3) I'm trying to duplicate as little as possible. For instance, I first hoped to simply create separate methods in the Service layer which were noted as Transactional with different qualifiers for the different TransactionManagers. The methods then referred to the same DAO object. However, this didn't work and I felt it may have been because it was a singleton DAO used in the Service and the same DAO couldn't be used for two different TransactionManagers. Thus, my next attempt was to create separate DAO classes implementing the same interface but with different Transactional qualifiers. However, when I do this I get an IllegalArgumentException when the DAO bean is injected into the Service bean.

    Based on the latest Spring and Hibernate, can someone guide me on what *should* be the best way to accomplish this? Below I will post some code and logs based on where I am but mostly I'd like your opinion on the "best" strategy. I can then employ it and post the results for follow-up.

    Spring.xml:
    HTML Code:
    <?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:p="http://www.springframework.org/schema/p"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans
    		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd
    		http://www.springframework.org/schema/context
    		http://www.springframework.org/schema/context/spring-context-3.0.xsd"
    	default-autowire="byName">
    	<context:annotation-config/>
    	<context:component-scan base-package="ds.irdm.saassvc" />
    	<tx:annotation-driven transaction-manager="transactionManager1"/>
    	<tx:annotation-driven transaction-manager="transactionManager2"/>
    
    	<bean id="wasCMDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    		<property name="jndiName" value="java:comp/env/jdbc/irdmcm" />
    		<property name="lookupOnStartup" value="false" />
    		<property name="cache" value="true" />
    		<property name="proxyInterface" value="javax.sql.DataSource" />
    	</bean>
    
    	<bean id="wasCISADataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    		<property name="jndiName" value="java:comp/env/jdbc/irdmcisa" />
    		<property name="lookupOnStartup" value="false" />
    		<property name="cache" value="true" />
    		<property name="proxyInterface" value="javax.sql.DataSource" />
    	</bean>
    
    	<bean id="sessionFactoryCM"
    		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    		<property name="dataSource" ref="wasCMDataSource" />
    		<property name="configurationClass">
    			<value>org.hibernate.cfg.AnnotationConfiguration</value>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
    				<prop key="hibernate.show_sql">true</prop>
    			</props>
    		</property>
    		<property name="annotatedClasses">
    			<list>
    				<value>ds.irdm.saassvc.model.SaasAuditEventQueue</value>
    			</list>
    		</property>
    	</bean>
    	
    	<bean id="sessionFactoryCISA"
    		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    		<property name="dataSource" ref="wasCMDataSource" />
    		<property name="configurationClass">
    			<value>org.hibernate.cfg.AnnotationConfiguration</value>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
    				<prop key="hibernate.show_sql">true</prop>
    			</props>
    		</property>
    		<property name="annotatedClasses">
    			<list>
    				<value>ds.irdm.saassvc.model.SaasAuditEventQueue</value>
    			</list>
    		</property>
    	</bean>
    
    
    	<bean id="transactionManager1"
    		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    		<property name="sessionFactory" ref="sessionFactoryCM" />
    		<qualifier value="irdmcm"/>
    	</bean>
    	
    	<bean id="transactionManager2"
    		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    		<property name="sessionFactory" ref="sessionFactoryCISA" />
    		<qualifier value="irdmcisa"/>
    	</bean>
    
    </beans>
    One of the 2 DAOs:
    Code:
    @Repository
    @Transactional("irdmcm")
    public class CmEventDAO extends EventDAOImpl {
    
    	private static Logger log = Logger.getLogger(CmEventDAO.class.getName());
    
    	public CmEventDAO(){}
    	
    	@Autowired
    	public void init( @Qualifier("sessionFactoryCM") SessionFactory factory) {
    		log.debug("==Calling Autowired init() method for SessionFactory");
    	    setSessionFactory(factory);
    	    log.debug("==SessionFactory: " + getSessionFactory());
    	}
    	
    	public void removeEvent( Integer id ) {
    		log.debug("removeEvent() id=" + id);
    		super.removeEvent( id );
    	}
    	
    	public List<SaasAuditEventQueue> listEvents() {
    		log.debug("listEvents()");
    		return super.listEvents();
    	}
    }
    Log of failure. After instantiating the DAO successfully, it fails on injecting it into the Service bean with IllegalArgumentException and no more detail.

    Code:
    [02/06/11 03:26:15:015 GMT] DEBUG annotation.AutowiredAnnotationBeanPostProcessor: Autowiring by type from bean name 'cm
    EventDAO' to bean named 'sessionFactoryCM'
    [02/06/11 03:26:15:015 GMT] DEBUG dao.CmEventDAO: ==Calling Autowired init() method for SessionFactory
    [02/06/11 03:26:15:015 GMT] DEBUG dao.CmEventDAO: ==SessionFactory: org.hibernate.impl.SessionFactoryImpl@76227622
    [02/06/11 03:26:15:015 GMT] DEBUG support.DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.s
    pringframework.transaction.config.internalTransactionAdvisor'
    [02/06/11 03:26:15:015 GMT] DEBUG annotation.AnnotationTransactionAttributeSource: Adding transactional method 'listEven
    ts' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; 'irdmcm'
    [02/06/11 03:26:15:015 GMT] DEBUG autoproxy.InfrastructureAdvisorAutoProxyCreator: Creating implicit proxy for bean 'cmE
    ventDAO' with 0 common interceptors and 1 specific interceptors
    [02/06/11 03:26:15:015 GMT] DEBUG framework.JdkDynamicAopProxy: Creating JDK dynamic proxy: target source is SingletonTa
    rgetSource for target object [.ds.irdm.saassvc.model.dao.CmEventDAO@27982798]
    [02/06/11 03:26:15:015 GMT] DEBUG support.DefaultListableBeanFactory: Finished creating instance of bean 'cmEventDAO'
    [02/06/11 03:26:15:015 GMT] DEBUG annotation.AutowiredAnnotationBeanPostProcessor: Autowiring by type from bean name 'ev
    entServiceImpl' to bean named 'cmEventDAO'
    [02/06/11 03:26:15:015 GMT]  INFO support.DefaultListableBeanFactory: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@434e434e: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,...,cisaEventDAO,cmEventDAO,...,wasCMDataSource,wasCISADataSource,sessionFactoryCM,sessionFactoryCISA,transactionManager1,transactionManager2,exporter,monitorBean]; root of factory hierarchy
    [02/06/11 03:26:15:015 GMT] DEBUG support.DisposableBeanAdapter: Invoking destroy() on bean with name 'sessionFactoryCM'
    
    [02/06/11 03:26:15:015 GMT]  INFO annotation.AnnotationSessionFactoryBean: Closing Hibernate SessionFactory
    [02/06/11 03:26:15:015 GMT]  INFO impl.SessionFactoryImpl: closing
    [02/06/11 03:26:15:015 GMT] ERROR servlet.DispatcherServlet: Context initialization failed
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'eventController': Injection of a
    utowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not aut
    owire field: private .ds.irdm.saassvc.service.EventService .ds.irdm.saassvc.controller.EventControll
    er.eventService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with n
    ame 'eventServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factor
    y.BeanCreationException: Could not autowire field: private .ds.irdm.saassvc.model.dao.CmEventDAO .ds
    .irdm.saassvc.service.EventServiceImpl.cmEventDAO; nested exception is java.lang.IllegalArgumentException
            at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(A
    utowiredAnnotationBeanPostProcessor.java:285)

  • #2
    I think your @transactional annotation isn't correct.

    You simply should have :
    @Transactional("transactionManager1")

    Comment


    • #3
      gwa, ok I tried that and while it didn't cause any new problems, it didn't fix any either. Thanks for the input.

      Comment

      Working...
      X