Announcement Announcement Module
Collapse
No announcement yet.
MyBatis + AbstractRoutingDataSource Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • MyBatis + AbstractRoutingDataSource

    Mark Fischer's example http://blog.springsource.com/2007/01...ource-routing/ works great for the most part, but I have a quirky problem.

    I have 3 data sources. When routing to the 1st and 3rd data source, everything works fine, but fails with the 2nd data source every time. The second just returns a null result set. The logs show that the connection is successful, but never returns anything. I can also successfully retrieve a result set in Toad. Any help would be greatly appreciated!

    Implementation Code:
    Code:
    /**
     * Load an existing Po entity
     * 
     */
    @Transactional
    public Po getPoByPoNumber(String poNumber) {
    	
    	// Get Po by Po number from the default CMC Reporting data source
    	Po po = poDAO.getPoByPoNumber(poNumber);
    	
    	// if the Po is null, then get Po by Po number from CLS Reporting data source
    	// THIS NEVER RETURNS A RESULT SET?!??!?!
    	if(po == null){
    		DataSourceContextHolder.setTargetDataSource(DataSourceEnum.CLS);
    		po = poDAO.getPoByPoNumber(poNumber);
    	}
    	
    	// if the Po is null, then get Po by Po number from MTL Reporting data source
    	// This returns a result set
    	if(po == null){
    		DataSourceContextHolder.setTargetDataSource(DataSourceEnum.MTL);
    		po = poDAO.getPoByPoNumber(poNumber);
    	}
    	
    	// if the Po is STILL null, then instantiate Po 
    	//and set the CreatedUsername to "No Matching PO"
    	if(po == null){
    		po = new Po();
    		po.setPoCreatedUsername("No Matching P0");
    	}
    	
    	return po;
    }
    ContextHolder:
    Code:
    public class DataSourceContextHolder {
    	private static final ThreadLocal<DataSourceEnum> contextHolder = 
    		new ThreadLocal<DataSourceEnum>();
    	
    	public static void setTargetDataSource(DataSourceEnum targetDataSource){
    		Assert.notNull(targetDataSource, "Target data source cannot be null");
    		contextHolder.set(targetDataSource);
    	}
    	
    	public static DataSourceEnum getTargetDataSource(){
    		return (DataSourceEnum) contextHolder.get();
    	}
    	
    	public static void resetDefaultDataSource(){
    		contextHolder.remove();
    	}
    }
    Enumerator:
    Code:
    public enum DataSourceEnum {
    	CMC,
    	CLS,
    	MTL
    }
    RoutingDataSource:
    Code:
    public class RoutingDataSource extends AbstractRoutingDataSource{
    
    	@Override
    	protected Object determineCurrentLookupKey() {	
    		return DataSourceContextHolder.getTargetDataSource();
    	}
    }
    Application Context:
    HTML Code:
    <!-- enable component scanning (beware that this does not enable mapper scanning!) -->    
    <context:component-scan base-package="com.test" />
    
    <!-- enable autowire -->
    <context:annotation-config />
    
    <!-- enable transaction demarcation with annotations -->
    <tx:annotation-driven />
    
    <bean id="parentDataSource" 
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource" 
    		abstract="true">
    	<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver"/>
    	<property name="username" value="***"/>
    	<property name="password" value="***"/>
    </bean>
    
    <bean id="cmcDataSource" parent="parentDataSource">
    	<property name="url" value="jdbc:jtds:sqlserver://localhost:3306/Database1"/>
    </bean>
    
    <bean id="clsDataSource" parent="parentDataSource">
    	<property name="url" value="jdbc:jtds:sqlserver://localhost:3306/Database2"/>
    </bean>
    
    <bean id="mtlDataSource" parent="parentDataSource">
    	<property name="url" value="jdbc:jtds:sqlserver://localhost:3306/Database3"/>
    </bean>
    
    <bean id="dataSource" class="com.test.util.datasource.RoutingDataSource">
    	<property name="defaultTargetDataSource" ref="cmcDataSource"/>
    	<property name="targetDataSources">
    		<map key-type="com.test.util.datasource.DataSourceEnum">
    			<entry key="CLS" value-ref="clsDataSource"/>
    			<entry key="MTL" value-ref="mtlDataSource"/>
    		</map>
    	</property>
    </bean>
    
    <!-- transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    	<property name="dataSource" ref="dataSource" />
    </bean>
    
    <!-- define the SqlSessionFactory, notice that configLocation is not needed when you use MapperFactoryBean -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    	<property name="dataSource" ref="dataSource" />
    	<property name="configLocation" value="classpath:mybatis-config.xml" />
    </bean>
    
    <!-- scan for mappers and let them be autowired -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    	<property name="basePackage" value="com.test.finance.dao" />
    </bean>
    
    <!-- Logging Aspect Bean -->
    <bean id="loggingInterceptor" class="com.test.util.logging.LoggingMethodInterceptor"/>
    
    <aop:config>
    	<aop:pointcut expression="execution(* com.test..*.* (..))" id="loggingPointcut"/>
    	<aop:advisor advice-ref="loggingInterceptor" pointcut-ref="loggingPointcut"/>
    </aop:config>
    MyBatis Config:
    HTML Code:
    <configuration>
    	<settings>
    		<!-- changes from the defaults -->
    		<setting name="lazyLoadingEnabled" value="false" />
    	</settings>
    	<typeAliases>
    		<typeAlias alias="Po" type="com.test.finance.domain.Po" />
    	</typeAliases>
    </configuration>
Working...
X