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)
相关文章
相关标签/搜索