1.配置多个数据源



    <bean id="dataSource1" class="org.logicalcobwebs.proxool.ProxoolDataSource" >

        <property name="driver" value="oracle.jdbc.driver.OracleDriver" />

        <property name="driverUrl" value="jdbc:oracle:thin:@xx.xx.xx.xx:1521:ORCL" />

        <property name="user" value="xx" />

        <property name="password" value="xx" />

        <!--数据源的别名 -->

        <property name="alias" value="dataSource1" />

        <!-- 空闲连接个数 默认为0 -->

        <property name="prototypeCount" value="4" />

        <!--最小连接数(默认5个) -->

        <property name="minimumConnectionCount" value="1" />

        <!--最大连接数(默认15个),超过了这个连接数,再有请求时,就排在队列中等候,最大的等待请求数由maximum-new-connections决定 -->

        <property name="maximumConnectionCount" value="30" />

        <!-- 如果侦察线程发现闲置连接,则会使用这个SQL语句来对这些连接进行检查 -->

        <property name="houseKeepingTestSql" value="select CURRENT_DATE" />

    </bean>



        <bean id="dataSource2" class="org.logicalcobwebs.proxool.ProxoolDataSource" >

        <property name="driver" value="oracle.jdbc.driver.OracleDriver" />

        <property name="driverUrl" value="jdbc:oracle:thin:@xx.xx.xx.xx:1521:ORCL" />

        <property name="user" value="xx" />

        <property name="password" value="xx" />

        <!--数据源的别名 -->

        <property name="alias" value="dataSource2" />

        <!-- 空闲连接个数 默认为0 -->

        <property name="prototypeCount" value="4" />

        <!--最小连接数(默认5个) -->

        <property name="minimumConnectionCount" value="1" />

        <!--最大连接数(默认15个),超过了这个连接数,再有请求时,就排在队列中等候,最大的等待请求数由maximum-new-connections决定 -->

        <property name="maximumConnectionCount" value="30" />

        <!-- 如果侦察线程发现闲置连接,则会使用这个SQL语句来对这些连接进行检查 -->

        <property name="houseKeepingTestSql" value="select CURRENT_DATE" />

    </bean>



2.扩展Spring的AbstractRoutingDataSource抽象类,实现动态数据源。  


AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是实现数据源的route的核心.这里


对该方法进行Override。



import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  

public class DynamicDataSource extends AbstractRoutingDataSource {  

    @Override  

    protected Object determineCurrentLookupKey() {  

        return DBContextHolder.getCustomerType();  

    }  

}


上下文DbContextHolder为一线程安全的ThreadLocal,具体代码如下:


public class DBContextHolder {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();  

    public static void setCustomerType(String customerType) {  

        contextHolder.set(customerType);  

    }  

    public static String getCustomerType() {  

        return contextHolder.get();  

    }  

    public static void clearCustomerType() {  

        contextHolder.remove();  

    }

}



3.配置动态数据源


将DynamicDataSourceBean加入到Spring的上下文xml配置文件中去,同时配置DynamicDataSource的targetDataSources(多数据源目标)属性的Map映射。


    <!-- ========配置动态数据源  ======== -->

    <bean id="dynamicDataSource" class="com.incon.framework.dataSource.DynamicDataSource" >  

        <property name="targetDataSources">  

            <map key-type="java.lang.String">  

                <entry value-ref="dataSource1" key="dataSource1"></entry>  

                <entry value-ref="dataSource2" key="dataSource12"></entry>  

            </map>  

        </property>  

        <property name="defaultTargetDataSource" ref="dataSource1"></property><!-- 默认使用dataSource的数据源 -->

    </bean>




4.使用动态数据源   


例子中DynamicDataSource是继承与AbstractRoutingDataSource,而AbstractRoutingDataSource又是继承于org.springframework.jdbc.datasource.AbstractDataSource,AbstractDataSource实现了统一的DataSource接口,所以DynamicDataSource同样可以当一个DataSource使用。


在ORM框架ibatis中的使用配置示例:


    <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">  

        <property name="configLocations" >

            <list>

                <value>classpath:config/ibatis/ibatis-config.xml</value>

<!--                   <value>classpath:sqlmap/xk/*SqlMap.xml</value>  -->

            </list>

        </property>

        <property name="lobHandler">   

            <ref local="oracleLobHandler" />

        </property>

        <property name="dataSource" ref="dynamicDataSource"/>

    </bean>




5.事务管理


使用动态数据源的时候,可以看出和使用单数据源的时候相比,在使用配置上几乎没有差别,在进行性事务管理配置的时候也没有差别:


使用ibatis时的事务管理配置示例:


    <!-- 数据连接事务 -->

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dynamicDataSource" />

    </bean>


6.动态数据源的管理控制


如何选择控制每个业务中需要的具体数据源,可是使用手动控制:



public class DynamicDataSourceTest {

    public static void main(String[]args){

        DynamicDataSourceTest ds = new DynamicDataSourceTest();

        ds.loginUser();

    }


    public void loginUser(){

        String[] locationPath={"config/spring/spring-common.xml"

        ,"config/spring/spring-pool.xml"

        ,"config/spring/spring-securitycode.xml"};

        ApplicationContext context =new ClassPathXmlApplicationContext(locationPath);


        DemoService dao = (DemoService) context.getBean("demoService", DemoService.class);  

        DBContextHolder.setCustomerType(TargetDataSourceEnum.dataSource1);   

        HashMap mappar = new HashMap();

        mappar.put("dm", "dm1");

        mappar.put("mc", "mc1");

        DemoJsonPage demoJsonPage = new DemoJsonPage();


        System.out.println("-------------"+dao.queryNjb().size());        

    }

}


也可以采用AOP的控制方式:


public enum TargetDataSourceEnum {

    dataSource1,dataSource2

}


import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;


/**

 * 在方法上使用,用于指定使用哪个数据源

 *

 */

@Target({ ElementType.METHOD, ElementType.TYPE })

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface TargetDataSource {

    TargetDataSourceEnum name();

}


import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.core.annotation.Order;

import org.springframework.stereotype.Component;


/**

 * 切换数据源Advice

 * @author

 */

@Aspect

@Order(-1)// 保证该AOP在@Transactional之前执行

@Component

public class DynamicDataSourceAspect {


    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);


    @Before("@annotation(ds)")

    public void changeDataSource(JoinPoint point, TargetDataSource ds) throws Throwable {

        String dsId = ds.name().name();

        logger.debug("Use DataSource : {} > {}", ds.name(), point.getSignature());

        DBContextHolder.setCustomerType(ds.name().name());

    }


    @After("@annotation(ds)")

    public void restoreDataSource(JoinPoint point, TargetDataSource ds) {

        logger.debug("Revert DataSource : {} > {}", ds.name(), point.getSignature());

        DBContextHolder.clearCustomerType();

    }


}



使用方法


    @TargetDataSource(name=TargetDataSourceEnum.dataSource1)

    @Override

    public List queryNjb(){

        return dbDao.query("demo.queryNjb");

    }