转载

Spring配置动态数据源

Spring配置动态数据源,是在大型应用中对数据进行切换。一个使用场景就是,万一数据库的master实例挂了怎么办,如何动态的将从数据库替代上去呢? 保证数据库正常的使用呢? 那么Spring动态数据源的配置,就可以很好的解决这个问题,可以将数据源动态切换,将数据源切换到备用的数据库中。

配置多数据源有多中方案:

方案一: 配置多个数据源, 多个数据源分别都有一个sqlSessionFactory, 在使用时分表注入,往哪个库写就就使用哪个sqlSessionFactory

缺点: 修改麻烦,不符合开闭原则

方案二: 配置多个数据源,多个数据源都是使用同一个sqlSessionFactory

优点: 易于维护

Spring 2.x 以后的版本中采用Proxy模式,就是我们在方案中实现一个虚拟的数据源,并且使用它来封装数据源选择逻辑,这样就可以有效的将数据源选择逻辑从Client中分离出来,Client提供选择所需的上下文,由虚拟的DataSource根据Client提供上下文来实现。由虚拟的DataSource根据Client提供的上下文来实现数据源的选择。

<!-- 配置数据源 value 为数据库配置文件内的参数-->
 <beanid="dataSource1"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
    <!-- 使用数据源一的连接配置, 连接名称自己命名,这里的命名规则为了使读者明白,故在后面添加了数字-->
        <propertyname="driverClassName"value="${jdbc.driverClassName1}"/>
        <propertyname="url"value="${jdbc.url1}"/>
        <propertyname="username"value="${jdbc.username1}"/>
        <propertyname="password"value="${jdbc.password1}"/>
        <propertyname="maxActive"value="${maxActive1}"/>
        <propertyname="maxWait"value="${maxWait1}"/>
        <propertyname="maxIdle"value="${maxIdle1}"/>
    </bean>


     <beanid="dataSource2"class="org.apache.commons.dbcp.BasicDataSource">
     <!-- 使用数据源二的连接配置-->
        <propertyname="driverClassName"value="${jdbc.driverClassName2}"/>
        <propertyname="url"value="${jdbc.url2}"/>
        <propertyname="username"value="${jdbc.username2}"/>
        <propertyname="password"value="${jdbc.password2}"/>
        <propertyname="maxActive"value="${maxActive2}"/>
        <propertyname="maxWait"value="${maxWait2}"/>
        <propertyname="maxIdle"value="${maxIdle2}"/>
    </bean>
    
    <!--
        配置一个动态的DynamicDataSource类 该类自己定义,  继承了AbstractRoutingDataSource
    -->
    <beanid="dataSource"class="com.jd.jr.dao.DynamicDataSource">
        <propertyname="targetDataSources">
            <mapkey-type="java.lang.String">
                <entryvalue-ref="dataSource1"key="dataSource1"></entry>
                <entryvalue-ref="dataSource2"key="dataSource2"></entry>
            </map>
        </property>
        <!-- 默认的是 dataSource1的数据源 -->
        <propertyname="defaultTargetDataSource"ref="dataSource1"></property>
    </bean>
    
    
    <!--创建myBatis itessession -->
    <beanid="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源-->
        <propertyname="dataSource"ref="dataSource1"/>
        <!--映射文件-->
        <propertyname="mapperLocations"value="classpath:mapper/*.xml"/>
        <!--配置数据表对应的Java实体类-->
        <propertyname="typeAliasesPackage"value="com.jd.jr.bean"/>
        <!--mybaits配置文件-->
        <propertyname="configLocation"value="classpath:mybaits-config.xml"/>
    </bean>

创建一个获取和设置上下文环境的类DataSourceContextHolder,主要负责改变上下文数据源的名称

public class DataSourceContextHolder{
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

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


    public static String getTableIndex(){
        return (String)tableIndexHolder.get();
    }

    public static void clearTableIndex(){
        tableIndexHolder.remove();
    }

    public static void setTableIndex(String tableIndex){
        tableIndexHolder.set(tableIndex);
    }

    public static void setDBType(String dbType){
        contextHolder.set(dbType);
    }

    public static String getDBType(){
        return ((String) contextHolder.get());
    }

    public static void clearDBType(){
        contextHolder.remove();
    }
}

创建动态数据源类:

DynamicDataSource:

/**
 * Author:    wangchangchun
 * Date:      2017-11-15
 * Description:
 */
public class DynamicDataSourceextends AbstractRoutingDataSource{

    @Override
    protected Object determineCurrentLookupKey(){
        return DataSourceContextHolder.getDBType();
    }

}

注意: 如果需要切换数据源, 那么最好在调用Service 前将数据库中数据进行切换

在Facade 层中进行切换数据源

@Component
public class TransactionOrderFadeImplimplements TransactionOrderFade{

    private Logger logger  =  LoggerFactory.getLogger(TransactionOrderFadeImpl.class);
    //注入自己的服务层
    @Resource
    private TransactionOrderService transactionOrderService;

    public BaseResponseVo ceateOrder(PayOrderCreateRequestVo request){
        //创建一个 ceateOrder
        BaseResponseVo  baseResponseVo  = null;
        if (request==null || request.getPayOrderListVo() ==null || request.getPayOrderListVo().size() == 0){
            throw  new NoDataException("0001", "传入的参数是没严格的初始化操作,传入的常数为空");
        
        }
        // 将数据库切换
        //logger.info("将数据库的数据源进行切换");
        /**
         *  对数据库进行切换  设置数据源  切换数据源最好在调用哪个Service 层中的具体的
         *  业务操作之前进行切换
         */
        DataSourceContextHolder.setDBType("dataSource2");
        //......
    }
    //......
}
原文  https://wangchangchung.github.io/2018/01/08/Spring配置动态数据源/
正文到此结束
Loading...