Spring+Mybatis 實現動態選擇數據源

有時候我們想要實現動態選擇數據源的功能,即在進行數據庫操作時選擇對具體的某個數據源進行操作。這個功能我們利用Spring+Mybatis 即可實現。

1.DataSourceSwitcher

Spring 提供了一個 AbstractRoutingDataSource 抽象類來幫助我們實現動態數據源功能,我們可以自定義一個類 DataSourceSwitcher 並繼承 AbstractRoutingDataSource ,在 DataSourceSwitcher 類中實現三個方法 clearDataSource、determineCurrentLookupKey 和 setDataSourceKey 就行。

public class DataSourceSwitcher extends AbstractRoutingDataSource {
    //因爲線程經常切換,所以將線程所分配的數據源存入 ThreadLocal中
    private static final ThreadLocal<String> dataSourceKey=new ThreadLocal<>();

    /**
     * 清除 ThreadLocal 存儲的數據源
     */
    public static void clearDataSource(){
        dataSourceKey.remove();
    }
    
    /**
     * 決定使用哪個數據庫
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        String dataSource=dataSourceKey.get();
        return dataSource;
    }

    /**
     * 設置數據源
     * @param dataSource
     */
    public static void setDataSourceKey(String dataSource){
        dataSourceKey.set(dataSource);
    }
}

2.配置 spring-mybatis.xml

 <!-- 引入配置文件-->
    <context:property-placeholder location="classpath:druid.properties"/>


    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${druid.username}" />
        <property name="password" value="${druid.password}" />
        <property name = "driverClassName" value = "${druid.driverClassName}" />

        <!-- 初始化連接數量 -->
        <property name="initialSize" value="${druid.initialSize}" />
        <!-- 最小空閒連接數 -->
        <property name="minIdle" value="${druid.minIdle}" />
        <!-- 最大併發連接數 -->
        <property name="maxActive" value="${druid.maxActive}" />
        <!-- 配置獲取連接等待超時的時間 -->
        <property name="maxWait" value="${druid.maxWait}" />

        <!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="${druid.timeBetweenEvictionRunsMillis}" />

        <!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="${druid.minEvictableIdleTimeMillis}" />
        <property name="validationQuery" value="${druid.validationQuery}" />
        <property name="testWhileIdle" value="${druid.testWhileIdle}" />
        <property name="testOnBorrow" value="${druid.testOnBorrow}" />
        <property name="testOnReturn" value="${druid.testOnReturn}" />

        <!-- 打開PSCache,並且指定每個連接上PSCache的大小 如果用Oracle,則把poolPreparedStatements配置爲true,mysql可以配置爲false。 -->
        <property name="poolPreparedStatements" value="${druid.poolPreparedStatements}" />
        <property name="maxPoolPreparedStatementPerConnectionSize"
                  value="${druid.maxPoolPreparedStatementPerConnectionSize}"/>
    </bean>

    <!--主庫,master -->
    <bean id="childDataSource1" parent="dataSource">
        <property name="url" value="${druid.url1}"/>
    </bean>
    <!--從庫,mybatisTest-->
    <bean id="childDataSource2" parent="dataSource">
        <property name="url" value="${druid.url2}"/>
    </bean>
 <!-- 配置數據源選擇器 -->
    <bean id="dataSourceSwitcher" class="com.datasource.switcher.DataSourceSwitcher">
        <!-- 使用的數據源 -->
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry key="query1" value-ref="childDataSource1"/>
                <entry key="update1" value-ref="childDataSource2"/>
            </map>
        </property>
        <!-- 默認數據源 -->
        <property name="defaultTargetDataSource" ref="childDataSource1"/>
    </bean>
<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--<property name="plugins" ref="mybatisInterceptor"/>-->
        <property name="dataSource" ref="dataSourceSwitcher" />
        <!-- 選擇數據源的plguin -->
        <property name="plugins" ref="dataSourceInterceptor"/>
        <!-- 自動掃描mapping.xml文件 -->
        <property name="mapperLocations" value="classpath:com/log/web/mapper/*Mapper.xml"></property>
    </bean>

    <!-- DAO接口所在包名,Spring會自動查找其下的類 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.log.web" />
        <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="dataSourceSwitcher" />
    </bean>

配置多個庫:

 <!--主庫,master -->
    <bean id="childDataSource1" parent="dataSource">
        <property name="url" value="${druid.url1}"/>
    </bean>
    <!--從庫,mybatisTest-->
    <bean id="childDataSource2" parent="dataSource">
        <property name="url" value="${druid.url2}"/>
    </bean>

配置數據源選擇器,在 targetDataSources 中配置將要使用的數據庫,key值用來選擇對應的數據庫

 <!-- 配置數據源選擇器 -->
    <bean id="dataSourceSwitcher" class="com.datasource.switcher.DataSourceSwitcher">
        <!-- 使用的數據源 -->
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry key="query1" value-ref="childDataSource1"/>
                <entry key="update1" value-ref="childDataSource2"/>
            </map>
        </property>

        <!-- 默認數據源 -->
        <property name="defaultTargetDataSource" ref="childDataSource1"/>
    </bean>

3.在調用方法時傳入想要使用的數據庫 key 值,即 targetDataSources 中配置的數據庫對應的 key 值來選擇數據庫。

 

總結:使用Spring+Mybatis 來實現動態選擇數據源就完成了!我們與常規的Spring+Mybatis 不同的只是增加了一個DataSourceSwitcher 類,並在 spring-mybatis.xml 中聲明 DataSourceSwitcher 和使用到的多個 dataSource,並在 SqlSessionFactory 和 DataSourceTransactionManager 的 dataSource 引用聲明的 DataSourceSwitcher

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章