zoukankan      html  css  js  c++  java
  • [转]SpringMVC+ Mybatis 配置多数据源 + 手动切换数据源

    正确可行的解决方法:使用Spring提供的AbstractRoutingDataSource类来根据请求路由到不同的数据源。具体做法是
    先设置两个不同的dataSource代表不同的数据源,再建一个总的dynamicDataSource,根据不同的请求去设置dynamicDataSource。代码如下:

    配置文件spring-mybatis.xml

    <!--统一的dataSource-->
    <bean id="dynamicDataSource" class="path.to.DynamicDataSource" >
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <!--通过不同的key决定用哪个dataSource-->
                <entry value-ref="dataSource" key="dataSource"></entry>
                <entry value-ref="mssqlDataSource" key="mssqlDataSource"></entry>
            </map>
        </property>
        <!--设置默认的dataSource-->
        <property name="defaultTargetDataSource" ref="dataSource">
        </property>
    </bean>
    
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="${jdbc.initialSize}"></property>
        <!-- 连接池最大数量 -->
        <property name="maxActive" value="${jdbc.maxActive}"></property>
        <!-- 连接池最大空闲 -->
        <property name="maxIdle" value="${jdbc.maxIdle}"></property>
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="${jdbc.minIdle}"></property>
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="${jdbc.maxWait}"></property>
    </bean>
    
    <!--电影票数据库是mssql2008,单独的数据库,配置如下-->
    <bean id="mssqlDataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${jdbc-mssql.driver}" />
        <property name="url" value="${jdbc-mssql.url}" />
        <property name="username" value="${jdbc-mssql.username}" />
        <property name="password" value="${jdbc-mssql.password}" />
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="${jdbc.initialSize}"></property>
        <!-- 连接池最大数量 -->
        <property name="maxActive" value="${jdbc.maxActive}"></property>
        <!-- 连接池最大空闲 -->
        <property name="maxIdle" value="${jdbc.maxIdle}"></property>
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="${jdbc.minIdle}"></property>
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="${jdbc.maxWait}"></property>
    </bean>
    
    <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dynamicDataSource" />
        <!-- 自动扫描mapping.xml文件 -->
        <property name="mapperLocations" value="classpath:path/to/mapping/*.xml"></property>
    </bean>
    
    <!-- DAO接口所在包名,Spring会自动查找其下的类 -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="path.to.dao" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>
    
    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dynamicDataSource" />
    </bean>

    DynamicDataSource.java

    public class DynamicDataSource extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            return CustomerContextHolder.getCustomerType();
        }
    }

    CustomerContextHolder.java

    public class CustomerContextHolder {
        public static final String DATA_SOURCE_MYSQL = "dataSource";
        public static final String DATA_SOURCE_MSSQL = "mssqlDataSource";
        //用ThreadLocal来设置当前线程使用哪个dataSource
        private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
        public static void setCustomerType(String customerType) {
            contextHolder.set(customerType);
        }
        public static String getCustomerType() {
            String dataSource = contextHolder.get();
            if (StringUtils.isEmpty(dataSource)) {
                return DATA_SOURCE_MYSQL;
            }else {
                return dataSource;
            }
        }
        public static void clearCustomerType() {
            contextHolder.remove();
        }
    }

    ServiceImpl.java

    CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_MSSQL);

    值得注意的是在CustomerContextHolder.java中使用了ThreadLocal类的set方法来设置当前线程要选择的dataSource,看一下set方法的源码:

    ThreadLocal.set()

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

    显而易见,获取当前线程,并且使用一个hashmap把需要存储的值设置进去。因为tomcat是用的线程池来处理每个请求,所以用ThreadLocal可以保证线程安全问题。同时这个AbstractRoutingDataSource类也值得好好研究一下。

    总结

    其实这个方案不仅仅可以用来处理不同数据源的问题,同时业务量上来之后需要把数据库进行主从分离或是把一个库分为多个库,都需要用到这样的做法。这次暴露的问题确实也了解了不少,继续学习吧!

    原地址:http://www.cnblogs.com/puyangsky/p/6133553.html

    亲测可用!

  • 相关阅读:
    微信小程序传值
    tp查询中2个表格中字段,比较大小
    isNaN与parseInt/parseFloat
    编程技巧之表格驱动编程
    RGB
    矩形重叠检测。
    经验搜索排名---google已经做过类似的了(我想多了)
    有关编程语言的认识
    Nodepad++ 资料整理
    lower()
  • 原文地址:https://www.cnblogs.com/raphael5200/p/7193670.html
Copyright © 2011-2022 走看看