python爬虫Java技术专题

SpringBoot整合多数据源,你会了吗?

2020-03-12  本文已影响0人  爱撒谎的男孩

导读

AbstractRoutingDataSource

实现

线程隔离ThreadLocal

/**
 * @Description ThreadLocal保存数据源,保持线程隔离
 * @Author CJB
 * @Date 2020/3/12 14:29
 */
public class DynamicThreadLocalHolder {
    //本地线程保存数据源
    private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    /**
     * 设置线程数据源
     */
    public static void setDataSource(String dataSource){
        threadLocal.set(dataSource);
    }

    /**
     * 获取本地线程的数据源,这里只是数据源的key
     * @return
     */
    public static String getDataSource(){
        return threadLocal.get();
    }

    /**
     * 清除数据源
     */
    public static void clearDataSource(){
        threadLocal.remove();
    }
}

动态数据源实现

/**
 * @Description 动态数据源的实现
 * @Author CJB
 * @Date 2020/3/12 14:27
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    /**
     * 决定使用哪个数据源
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        //从ThreadLocal中获取数据源的beanName
        return DynamicThreadLocalHolder.getDataSource();
    }
}

多数据源配置

/**
 * @Description 数据源的配置
 * @Author CJB
 * @Date 2020/3/9 13:45
 */
@Configuration
@MapperScan(basePackages = {"com.vivachek.service.dao","com.vivachek.service.dao2"})
public class DatasourceConfig {

    /**
     * 注入数据源1
     */
    @ConfigurationProperties(prefix = "spring.datasource1")
    @Bean(value = "dataSource1")
    public DataSource dataSource1() {
        return new DruidDataSource();
    }

    /**
     * 第二个数据源
     */
    @Bean(name = "dataSource2")
    @ConfigurationProperties(prefix = "spring.datasource2")
    public DataSource dataSource2() {
        return new DruidDataSource();
    }

    /**
     * 动态数据源
     *
     * @return
     */
    @Bean
    public DynamicDataSource dynamicDataSource() {
        DynamicDataSource dataSource = new DynamicDataSource();
        //默认数据源,在没有切换数据源的时候使用该数据源
        dataSource.setDefaultTargetDataSource(dataSource2());
        HashMap<Object, Object> map = Maps.newHashMap();
        map.put("dataSource1", dataSource1());
        map.put("dataSource2", dataSource2());
        //设置数据源Map,动态切换就是根据key从map中获取
        dataSource.setTargetDataSources(map);
        return dataSource;
    }


    /**
     * 和Mybatis整合必须设置SqlSessionFactory的数据源为动态数据源
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        //此处必须设置动态数据源
        factoryBean.setDataSource(dynamicDataSource());
        factoryBean.setVfs(SpringBootVFS.class);
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        factoryBean.setConfiguration(configuration);
        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/**/*.xml"));
        return factoryBean.getObject();
    }

    /**
     * 设置事务管理器
     *
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}

AOP动态切换

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ChangeSource {
    /**
     * 数据源,动态数据源默认的是datasource1,这里默认的直接dataSource2
     * @return
     */
    String value() default "dataSource1";
}
/**
 * @Description 切面
 * @Author CJB
 * @Date 2020/3/12 16:18
 */
@Aspect
@Component
@Slf4j
public class ChangeSourceAspect {
    @Pointcut("@annotation(com.vivachek.core.aop.ChangeSource)")
    public void pointcut() {
    }

    /**
     * 在方法执行之前往ThreadLocal中设置值
     */
    @Before(value = "pointcut()")
    public void beforeOpt(JoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        ChangeSource changeSource = method.getAnnotation(ChangeSource.class);
        log.info("[Switch DataSource]:" + changeSource.value());
        DynamicThreadLocalHolder.setDataSource(changeSource.value());
    }

    /**
     * 结束之后清除
     */
    @After(value = "pointcut()")
    public void afterOpt() {
        DynamicThreadLocalHolder.clearDataSource();
        log.info("[change Default DataSource]");
    }

}

思考

源码

【数据源】即可。

image

另外一种实现方式

上一篇下一篇

猜你喜欢

热点阅读