数据库多数据源自动选择实现

1、写对应枚举的数据源

public enum DataSourceEnum {
    DB1("空铁", "datasource1"),
    DB2("同程", "datasource2"),
    DB3("账号", "datasource3");
    private String name;
    private String value;
    DataSourceEnum(String name, String value) {
        this.name = name;
        this.value = value;
    }
    public String getName(){
        return this.name;
    }
    public String getValue() {
        return this.value;
    }
}

2、实现注解功能

可以使用注解的方式,注解sql使用哪个数据源,在执行sql的时候,就会自动选择对应的数据源

import java.lang.annotation.*;

@Target({ElementType.METHOD,ElementType.TYPE})    //固定写法
@Retention(RetentionPolicy.RUNTIME)    //固定写法
@Documented    //固定写法
public @interface DataSource       //可自定义注解名字
{
    DataSourceEnum value() default DataSourceEnum.DB1;   //默认的数据源,此处的数据源是自己写的配置
}

3、切面,实现注解形式自动切换数据源

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
@Order(-1)
public class DataSourceAspect {
    //↓↓↓此处的DataSource路径是注解的路径,通过注解实现切面功能
    @Pointcut("@within(com.ccservice.searchordernum.config.DataSource)||@annotation(com.ccservice.searchordernum.config.DataSource)")
    public void pointCut(){}
    //↓↓↓annotation中的datasource是下面方法中的参数。参数中的datasource是注解类
    @Before("pointCut() && @annotation(dataSource)")
    public void doBefor(DataSource dataSource){
        log.info("选择数据源:{}", dataSource.value().getName());  //此处加一个日志,打印出来切换的数据源
        //此处设置切换数据源。动态切换。后续我们设置数据源的时候以枚举的value作为key,所以此处设置value就达到了切换数据源的效果
        DataSourceContextHolder.setDatasource(dataSource.value().getValue());  
    }
    @After("pointCut()")
    public void doAfter() {
        DataSourceContextHolder.clear();  //之后进行数据源清空
    }
}

4、配置druid监控页面

import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DataSourceConfiguration {
    @Bean
    public ServletRegistrationBean startViewServlet(){
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
        // IP白名单  此处最好把黑白名单去掉,暂时不清楚怎么弄的
        servletRegistrationBean.addInitParameter("allow","127.0.0.1");
        // IP黑名单(共同存在时,deny优先于allow)
        servletRegistrationBean.addInitParameter("deny","127.0.0.1");
        //控制台管理用户   配置账号密码等
        servletRegistrationBean.addInitParameter("loginUsername","admin");
        servletRegistrationBean.addInitParameter("loginPassword","123456");
        //是否能够重置数据
        servletRegistrationBean.addInitParameter("resetEnable","false");
        return servletRegistrationBean;
    }
    @Bean
    public FilterRegistrationBean statFilter(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
        //添加过滤规则
        filterRegistrationBean.addUrlPatterns("/*");
        //忽略过滤的格式
        filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}

5、数据源配置功能类

//该类用于配置数据源。设置好既有数据源后,后续可以进行配置使用哪个。配合切面,可以达到动态切换的功能
public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder =new InheritableThreadLocal<>();
    public static void setDatasource(String db) {
        contextHolder.set(db);
    }
    public static String getDatasource(){
        return contextHolder.get();
    }
    public static void clear(){
        contextHolder.remove();
    }
}

6、多数据源关联类

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
//将多个数据源关联起来
public class MultipleDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDatasource();
    }
}

7、数据源、数据库等设置类

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 *     MybatisPlus配置
 * </p>
 * @author geekidea
 * @since 2018-11-08
 */
@Configuration
@MapperScan({"com.ccservice.**.mapper"})
@Slf4j
public class MyBatisPlusConfig {

    /**
     * mybatis-plus分页插件<br>   固定,不需要修改
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

    /**
     * SQL执行效率插件    固定,不需要修改
     */
    @Bean
    @Profile({"dev","test"})// 设置 dev test 环境开启
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(1000);
        performanceInterceptor.setFormat(true);
        return performanceInterceptor;
    }

    /**
     * 数据源配置,配置多个数据源。使用配置文件,配合DRUID数据源配置类,自动装配数据源。
     */

    @Bean(name = "datasource1")
    @ConfigurationProperties(prefix = "spring.commons.datasource1" )
    public DataSource db1() {
        log.info("开始加载数据源1");
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "datasource2")
    @ConfigurationProperties(prefix = "spring.commons.datasource2" )
    public DataSource db2() {
        log.info("开始加载数据源2");
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "datasource3")
    @ConfigurationProperties(prefix = "spring.commons.datasource3" )
    public DataSource db3() {
        log.info("开始加载数据源3");
        return DruidDataSourceBuilder.create().build();
    }

    /**************************************/
    
    /**
     * 动态数据源配置   将上面配置的多个数据源,设置到多数据源关联配置中
     * @return
     */
    @Bean
    @Primary
    public DataSource multipleDataSource(@Qualifier("datasource1") DataSource db1,
                                         @Qualifier("datasource2") DataSource db2,
                                         @Qualifier("datasource3") DataSource db3) {
        log.info("开始添加数据源到适配器");
        //多数据源关联类  new出来的对象是单例的,对应单独的数据源配置类---》5
        MultipleDataSource multipleDataSource = new MultipleDataSource();
        //将多数据源存在map中,后续进行切换配置
        Map< Object, Object > targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceEnum.DB1.getValue(), db1);
        targetDataSources.put(DataSourceEnum.DB2.getValue(), db2);
        targetDataSources.put(DataSourceEnum.DB3.getValue(), db3);
        //添加数据源  添加到数据源中
        multipleDataSource.setTargetDataSources(targetDataSources);
        //设置默认数据源 
        multipleDataSource.setDefaultTargetDataSource(db1);
        log.info("数据源适配器配置完成");
        return multipleDataSource;
    }

    /**
     * 数据库连接池工厂,设置的数据源是关联过后的多数据源。
     */

    @Bean("sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        log.info("整理数据源工厂");
        MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
        log.info("设置数据源");
        sqlSessionFactory.setDataSource(multipleDataSource(db1(),db2(),db3()));
        //sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/*/*Mapper.xml"));
        MybatisConfiguration configuration = new MybatisConfiguration();
        //configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setCacheEnabled(false);
        sqlSessionFactory.setConfiguration(configuration);
        sqlSessionFactory.setPlugins(new Interceptor[]{ //PerformanceInterceptor(),OptimisticLockerInterceptor()
                paginationInterceptor() //添加分页功能
        });
//        sqlSessionFactory.setGlobalConfig(globalConfiguration());
        log.info("数据源工厂完毕");
        return sqlSessionFactory.getObject();
    }

    /*@Bean
    public GlobalConfiguration globalConfiguration() {
        GlobalConfiguration conf = new GlobalConfiguration(new LogicSqlInjector());
        conf.setLogicDeleteValue("-1");
        conf.setLogicNotDeleteValue("1");
        conf.setIdType(0);
        //conf.setMetaObjectHandler(new MyMetaObjectHandler());
        conf.setDbColumnUnderline(true);
        conf.setRefresh(true);
        return conf;
    }*/
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写代码的喵o

请作者吃包辣条可好

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值