美文网首页java学习SpringFrameworkJava学习笔记
spring+mybatis多数据源配置与使用

spring+mybatis多数据源配置与使用

作者: lothar_cly | 来源:发表于2016-05-16 17:18 被阅读7128次
    Spring+Mybatis的多数据源配置。

    上午接到一个需求,在一个项目中增加一个数据源的配置。某些方法在操作的时候需要使用不同的数据库。记录一下完成步骤。

    刚拿到这个需求的时候,是准备直接配置多个dataSource的,这也是最简单粗暴的解决方法。

        <bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource"
            destroy-method="close" init-method="init">
            <property name="driverClassName" value="${driverClassName}" />
            <property name="url" value="${url}" />
            <property name="username" value="${username}" />
            <property name="password" value="${password}" />
        </bean>
        <bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource"
            destroy-method="close" init-method="init">
            <property name="driverClassName" value="${driverClassName2}" />
            <property name="url" value="${url2}" />
            <property name="username" value="${username2}" />
            <property name="password" value="${password2}" />
        </bean>
    

    这样就有了两个dataSource了。然后在配置两个sqlSessionFactory

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource1" />
            <property name="mapperLocations"
                value="classpath*:com/core/persistence/**/*Mapper*.xml" />
            <property name="typeAliasesPackage" value="com.core.domain.***" />
        </bean>
    

    然后在使用两个MapperScannerConfigurer和他们都对应上。

        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="annotationClass" value="javax.annotation.Resource"/>
            <property name="sqlSessionFactoryBeanName" ref="sqlSessionFactory"/>
            <property name="basePackage" value="com.core.persistence" />
        </bean>
    

    这样好像就可以了。正确的mapperLocationsbasePackage对应上就应该没什么问题。
    上面的都是我想的!!当然我也这么尝试过了。遇到的问题是MapperScannerConfigurer告诉我,There is more than one bean of 'SqlSessionFactory' type。告诉我这个SqlSessionFactory只能配置一个。但是呢!

     /*   <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
     *       <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
     *       <!-- optional unless there are multiple session factories defined -->
     *       <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
     *   </bean>
     * }
     * </pre>
     *
     * @author Hunter Presnall
     * @author Eduardo Macarron
     *
     * @see MapperFactoryBean
     * @see ClassPathMapperScanner
     * @version $Id$
     */
    public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {}
    

    源码里的注释说是可以配置多个。这时候我已经不知道怎么通过配置来完成这个需求了。
    使用第二种办法!配置多个数据源,然后通过代码在完成数据库的切换。AOP是一个非常好的实现方式。平时用AOP也不是很多,然后就试试看。数据源的配置同上。然后写一个MultipleDataSource类,来根据KEY选择数据源进行操作。

    public class MultipleDataSource extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            return DataSourceTypeManager.get();
        }
    }
    
        <bean id="dataSource" class="MultipleDataSource">
            <property name="defaultTargetDataSource" ref="dataSource1" />
            <property name="targetDataSources">
                <map key-type="DataSourceType">
                    <entry key="1" value-ref="dataSource1"/>
                    <entry key="2" value-ref="dataSource2"/>
                    <!-- 这里还可以加多个dataSource -->
                </map>
            </property>
        </bean>
    
    public class DataSourceTypeManager {
    
        private static final ThreadLocal<DataSourceType> dataSourceTypes = new ThreadLocal<DataSourceType>() {
            @Override
            protected DataSourceType initialValue() {
                return DataSourceType.1;
            }
        };
    
        public static DataSourceType get() {
            return dataSourceTypes.get();
        }
    
        public static void set(DataSourceType dataSourceType) {
            dataSourceTypes.set(dataSourceType);
        }
    
        public static void reset() {
            dataSourceTypes.set(DataSourceType.CN);
        }
    

    前面的主要用途就是完成对数据库连接的配置。同时配置如何标识dataSource

    public class DataSourceInterceptor {
    
        public void setDataSourceIs1(){
            DataSourceTypeManager.set(DataSourceType.1);
        }
    
        public void setDataSourceIs2(){
            DataSourceTypeManager.set(DataSourceType.2);
        }
    }
    

    用来切换数据源。

        <bean id="dataSourceInterceptor" class="DataSourceInterceptor" />
        <aop:config>
            <aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor">
                <aop:pointcut id="2" expression="execution(* *..*Information*.*(..)))" />
                <aop:before method="setDataSourceIs2" pointcut-ref="2"/>
                <aop:after method="setDataSourceIs1" pointcut-ref="2"/>
            </aop:aspect>
        </aop:config>
    

    这就是整个的关键所在,在包含Information的类中的方法执行时切换数据源,默认使用dataSource1。这个需求就已经完成了。
    第一种方法我没有成功。第二种方法也是我使用的方法。感觉第二种方法更加的好用,容易扩展,切换的粒度可以很好的控制。

    ==========分割线========
    我本来的想法是在执行包含information字样的类在执行时切换数据源,后来发现一个问题,就是除了上面那种类的方法执行时正常的数据源,其他类在执行的过程中会出现数据源随机切换的问题,所以我不得已在AOP后执行了切回去的操作。暂时好用。我还在查原因!

    相关文章

      网友评论

      • 杜小degree:数据源出现错乱我一开始也遇到了,后来我是定义了切面,执行master中的service时切换成master数据源,执行slave中的service时切换成slave数据源。想问下楼主,实际线上中还出现过数据源错乱的情形吗
      • 94e7f0821c37:随机切换是因为线程池?
        杜小degree:数据源出现错乱我一开始也遇到了,后来我是定义了切面,执行master中的service时切换成master数据源,执行slave中的service时切换成slave数据源。想问下楼主,实际线上中还出现过数据源错乱的情形吗
        7圈电池:线程池是保证线程安全性, 切换只能看自己了, 比如我用aop , 可以定义一个切入点,全部用slave数据源, 我在获取连接前更改了 Type, 那么由于TheadLocal的安全性,当获取连接就会获取这个Type值, 根据Type值 为 key, 取实际的数据源(val),从而实现多库的切换啊!

      本文标题:spring+mybatis多数据源配置与使用

      本文链接:https://www.haomeiwen.com/subject/jivbrttx.html