Spring+ibatis 多数据源的配置和使用

来源:互联网 发布:美国历年非农数据统计 编辑:程序博客网 时间:2024/05/16 02:24
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");
    }





0 0
原创粉丝点击