Spring 配置多個數據源,並實現動態切換

 由於最近項目公司須要,須要在mybatis上配置多數據源。多數據源在jpa中配置仍是相對簡單的,由於個個數據源對應的持久化類相對獨立。可是在mybatis上配置仍是比較麻煩的。網上找到的教程大多對於目前的項目是須要有比較大的改動的。看到關於不是用spring實現多數據源用到了aop。java

    參考了這篇文章 http://blog.csdn.net/gaofuqi/article/details/46417281。可是這篇文章上缺乏一些細節。對於技術比較紮實的人來講,固然沒有什麼問題。我主要是把缺失的細節補上去。mysql

    

<!-- base dataSource -->
    <bean name="mysqlDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${db.mysql.url}" />
        <property name="username" value="${db.mysql.user}" />
        <property name="password" value="${db.mysql.password}" />
        
        <!-- 配置監控統計攔截的filters -->
        <property name="filters" value="mergeStat,wall,log4j2" />
        
        <property name="initialSize" value="5" />
        <property name="maxActive" value="100" />
        <property name="minIdle" value="10" />
        <property name="maxWait" value="60000" />
        <property name="validationQuery" value="SELECT 'x'" />
        <property name="testOnBorrow" value="true" />
        <property name="testOnReturn" value="true" />
        <property name="testWhileIdle" value="true" />
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="removeAbandoned" value="true" />
        <property name="removeAbandonedTimeout" value="1800" />
        <property name="logAbandoned" value="true" />
    </bean>

    <bean name="oracleDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${db.oracle.url}" />
        <property name="username" value="${db.oracle.user}" />
        <property name="password" value="${db.oracle.password}" />

        <!-- 配置監控統計攔截的filters -->
        <property name="filters" value="mergeStat,wall,log4j2" />

        <property name="initialSize" value="5" />
        <property name="maxActive" value="100" />
        <property name="minIdle" value="10" />
        <property name="maxWait" value="60000" />
        <!--<property name="validationQuery" value="SELECT 1 FROM DUAL'" />-->
        <property name="testOnBorrow" value="true" />
        <property name="testOnReturn" value="true" />
        <property name="testWhileIdle" value="true" />
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="removeAbandoned" value="true" />
        <property name="removeAbandonedTimeout" value="1800" />
        <property name="logAbandoned" value="true" />
    </bean>

    <!-- 編寫spring 配置文件的配置多數源映射關係 -->
    <bean class="com.sanjiang.weixin.xd_admin.commons.base.DynamicDataSource" id="dataSource">
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry value-ref="mysqlDataSource" key="mysql"></entry>
                <entry value-ref="oracleDataSource" key="oracle"></entry>
            </map>
        </property>
        <property name="defaultTargetDataSource" ref="mysqlDataSource">
        </property>
    </bean>

一開始我覺得這邊配置了默認的datasource,而後程序就會用默認的mysqlDataSource。後來我發現我天真了,系統起不來了,由於我在系統中是配置了事務的。spring

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

定義一個能夠設置當前線程的變量的工具類,用於設置對應的數據源名稱:sql

public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
    /**
     * @Description: 設置數據源類型
     * @param dataSourceType  數據庫類型
     * @return void
     * @throws
     */
    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    /**
     * @Description: 獲取數據源類型
     * @param
     * @return String
     * @throws
     */
    public static String getDataSourceType() {
        return contextHolder.get();
    }

    /**
     * @Description: 清除數據源類型
     * @param
     * @return void
     * @throws
     */
    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

定義一個aop處理類在數據庫事務開啓以前切換數據庫數據庫

public class DataSourceAspect implements MethodBeforeAdvice,AfterReturningAdvice
{

    @Override
    public void afterReturning(Object returnValue, Method method,
            Object[] args, Object target) throws Throwable {
        // TODO Auto-generated method stub
        DataSourceContextHolder.clearDataSourceType();
    }

    @Override
    public void before(Method method, Object[] args, Object target)
            throws Throwable {

        if (method.isAnnotationPresent(DataSource.class))
        {
            DataSource datasource = method.getAnnotation(DataSource.class);
            DataSourceContextHolder.setDataSourceType(datasource.name());
        }
        else
        {
            DataSourceContextHolder.setDataSourceType(DataSourceConst.MYSQL);
        }


    }
}



@Retention(RetentionPolicy.RUNTIME)
@interface DataSource {

    String name();
}

public class DataSourceConst {

    public static final String MYSQL="mysql";
    public static final String ORACLE="oracle";
}
<!-- 配置切面 -->
    <aop:config>
        <aop:pointcut id="transactionPointCut" expression="execution(* com.sanjiang365.weixin.xd_admin.*.service..*.*(..))" />
        <aop:advisor pointcut-ref="transactionPointCut"
                     advice-ref="transactionAdvice" order="2" />

        <aop:advisor advice-ref="dataSourceExchange" pointcut-ref="transactionPointCut" order="1"/>
    </aop:config>

這也是我參考的文章中沒有補全的。express

使用方法的話mybatis

查詢的話,添加下面的代碼oracle

DataSourceContextHolder.setDataSourceType(DataSourceConst.ORACLE);

 

若是涉及到事務的話,在在Service的接口中添加註解就ok了ide

@DataSource(name = DataSourceConst.ORACLE)
相關文章
相關標籤/搜索