天天看点

Spring AbstractRoutingDataSource 实现多数据源

1 编写DataSourceHolder

public class DataSourceHolder {

    private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();

    /**
     * 获取当前线程的数据源路由的key
     */
    public static String getKey() {
        return threadLocal.get();
    }

    /**
     * 绑定当前线程数据源路由的key
     * 使用完成后必须调用removeRouteKey()方法删除
     */
    public static void setKey(String key) {
        threadLocal.set(key);
    }

    /**
     * 删除与当前线程绑定的数据源路由的key
     */
    public static void removeKey() {
        threadLocal.remove();
    }
}
           

2 编写MultipleDataSource实现AbstractRoutingDataSource

public class MultipleDataSource extends AbstractRoutingDataSource {

    //通过这个值切换数据源
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceHolder.getKey();
    }

}
           

3 编写注解 @DataSourceKey

@Target({ElementType.METHOD})
@Retention(RUNTIME)
public @interface DataSourceKey {
    //要切换的数据源,
    String value();
}
           

4 编写aop DataSourceAspect拦截注解

@Aspect
@Component
public class DataSourceAspect {

    private final Log logger = LogFactory.getLog(this.getClass());

    @Around("@annotation(changeDataSource)")
    public Object aroundAdvice(ProceedingJoinPoint point, DataSourceKey changeDataSource) throws Throwable {
        try {
            //方法执行前修改数据源
            DataSourceHolder.setKey(changeDataSource.value());
            return point.proceed();
        } catch (Exception e) {
            logger.error(e.getMessage());
        } finally {
            //方法执行后切换到默认数据源
            DataSourceHolder.removeKey();
        }
        return null;
    }

}
           

5 编写xml

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
    <property name="driverClassName" value="${jdbc.driver}"/>
    <!-- 配置初始化大小、最小、最大 -->
    <property name="initialSize" value="1"/>
    <property name="minIdle" value="1"/>
    <property name="maxActive" value="300"/>
    <!-- 配置获取连接等待超时的时间 -->
    <property name="maxWait" value="60000"/>
    <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
    <property name="timeBetweenEvictionRunsMillis" value="60000"/>
    <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
    <property name="minEvictableIdleTimeMillis" value="300000"/>
    <property name="validationQuery" value="SELECT 'x' FROM DUAl"/>
    <property name="testWhileIdle" value="true"/>
    <property name="testOnBorrow" value="false"/>
    <property name="testOnReturn" value="false"/>
    <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
    <property name="poolPreparedStatements" value="true"/>
    <property name="maxPoolPreparedStatementPerConnectionSize" value="20"/>
    <!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 -->
    <property name="filters" value="stat"/>
</bean>
<bean id="demo" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="goisan_gemini"/>
    <property name="password" value="gemini"/>
    <property name="driverClassName" value="${jdbc.driver}"/>
    <!-- 配置初始化大小、最小、最大 -->
    <property name="initialSize" value="1"/>
    <property name="minIdle" value="1"/>
    <property name="maxActive" value="300"/>
    <!-- 配置获取连接等待超时的时间 -->
    <property name="maxWait" value="60000"/>
    <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
    <property name="timeBetweenEvictionRunsMillis" value="60000"/>
    <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
    <property name="minEvictableIdleTimeMillis" value="300000"/>
    <property name="validationQuery" value="SELECT 'x' FROM DUAl"/>
    <property name="testWhileIdle" value="true"/>
    <property name="testOnBorrow" value="false"/>
    <property name="testOnReturn" value="false"/>
    <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
    <property name="poolPreparedStatements" value="true"/>
    <property name="maxPoolPreparedStatementPerConnectionSize" value="20"/>
    <!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 -->
    <property name="filters" value="stat"/>
</bean>

<bean id="multipleDataSource" class="com.goisan.sdcenter.dynamicdatasource.MultipleDataSource" lazy-init="true">
    <property name="targetDataSources">
        <map key-type="java.lang.String">
            <!-- key数据源名称,通过key来实现切换数据源 -->
            <entry key="dataSource" value-ref="dataSource"/>
            <entry key="demo" value-ref="demo"/>
        </map>
    </property>
    <!-- 默认数据源 -->
    <property name="defaultTargetDataSource" ref="dataSource"/>
</bean>
           

继续阅读