• Springboot+mybatis动态设置数据源


    1.修改properties(spring默认的)数据源的前缀 新增中台数据

    2编写数据源上下文
    mport java.util.List;

    public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new InheritableThreadLocal<String>();


    public static final String DEFAULT_DS ="defaultDs";
    /*
    * 管理所有的数据源id;
    * 主要是为了判断数据源是否存在;
    */
    public static List<String> dataSourceIds = new ArrayList<String>();

    // 设置数据源类型
    public static void setDataSourceType(String datasource) {
    contextHolder.set(datasource);
    }

    // 获取数据源类型
    public static String getDataSourceType() {
    return (String) contextHolder.get();
    }

    // 清除数据源类型
    public static void clearDataSourceType() {
    contextHolder.remove();
    }

    //判断指定DataSource当前是否存在
    public static boolean containsDataSource(String dataSourceId){

    return dataSourceIds.contains(dataSourceId);

    }
    }


    3 继承AbstractRoutingDataSource实现类DynamicDataSource(关键)
        AbstractRoutingDataSource抽象类知识,实现AOP动态切换的关键
        1.AbstractRoutingDataSourcedetermineTargetDataSource()方法中获取数据源 
    Object lookupKey = determineCurrentLookupKey();
    DataSource dataSource = this.resolvedDataSources.get(lookupKey);

    根据determineCurrentLookupKey()得到Datasource,并且此方法是抽象方法,应用可以实现
        2.resolvedDataSources的值根据targetDataSources所得
    afterPropertiesSet()方法中(在@Bean所在方法执行完成后,会调用此方法):
    Map.Entry<Object, Object> entry : this.targetDataSources.entrySet()
        3.然后在xml中使用<bean>或者代码中@Bean 设置DynamicDataSource的defaultTargetDataSource(默认数据源)和targetDataSources(多数据源)
        4.利用自定义注解,AOP拦截动态的设置ThreadLocal的值
        5.在DAO层与数据库建立连接时会根据ThreadLocal的key得到数据源
    代码:getConnection()
    determineTargetDataSource().getConnection();(determineTargetDataSource返回的是DataSource)




    package com.lm.config.datasource;

    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

    public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
    return DataSourceContextHolder.getDataSourceType();
    }
    }

    4配置多数据源
    @Configuration
    public class DataSourceConfig {

    @Bean(name = "defaultDs")
    @ConfigurationProperties(prefix = "jph.datasource") // application.properteis中对应属性的前缀
    public DataSource dataSource1() {
    return DataSourceBuilder.create().build();
    }




    @Bean(name = "ziKuDs")
    @ConfigurationProperties(prefix = "ziku.datasource")
    public DataSource dataSource2() {
    return DataSourceBuilder.create().build();
    }

    /**
    * 动态数据源: 通过AOP在不同数据源之间动态切换
    * @return
    */
    @Bean(name = "dynamicDS")
    @Primary //优先使用
    public DataSource dataSource() {
    DynamicDataSource dynamicDataSource = new DynamicDataSource();
    // 默认数据源
    dynamicDataSource.setDefaultTargetDataSource(dataSource1());

    // 配置多数据源
    Map<Object, Object> dsMap = new HashMap(4);
    dsMap.put("defaultDs", dataSource1());
    dsMap.put("ziKuDs", dataSource2());

    dynamicDataSource.setTargetDataSources(dsMap);

    return dynamicDataSource;
    }
    }

    5配置mybatis的核心类 (SqlSessionTemplate
    1)精品汇
    @Configuration
    @MapperScan(basePackages = {"com.lm.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory1")
    public class jphDbConfig {

    @Autowired
    @Qualifier("defaultDs")
    private DataSource defaultDs;


    @Bean
    @Primary
    public SqlSessionFactory sqlSessionFactory1() throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(defaultDs);
    return factoryBean.getObject();
    }

    @Bean
    @Primary
    public SqlSessionTemplate sqlSessionTemplate1() throws Exception {
    SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory1()); // 使用上面配置的Factory
    return template;
    }
    }

    2)中台

    @Configuration
    @MapperScan(basePackages = {"com.ziku.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory2")
    public class ZikuDbConfig {

    @Autowired
    @Qualifier("ziKuDs")
    private DataSource zikuDs;


    @Bean
    public SqlSessionFactory sqlSessionFactory2() throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(zikuDs); // 使用titan数据源, 连接titan

    return factoryBean.getObject();

    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate2() throws Exception {
    SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory2()); // 使用上面配置的Factory
    return template;
    }
    }

    6 为了方便使用 我们使用aop加注解的方式来切换数据源
    /**

    * 在方法上使用,用于指定使用哪个数据源
    */

    @Target({ ElementType.METHOD, ElementType.TYPE })

    @Retention(RetentionPolicy.RUNTIME)

    @Documented
    public @interface TargetDataSource {
    String value() default "defaultDs";
    }



    /**

    * 切换数据源Advice
    */
    @Aspect

    @Order(-10)//保证该AOP@Transactional之前执行

    @Component
    public class DynamicDataSourceAspect {

    /*

    * @Before("@annotation(TargetDataSource)")
    * 的意思是:
    * @Before:在方法执行之前进行执行:

    * @annotation(targetDataSource)
    * 会拦截注解targetDataSource的方法,否则不拦截;
    */

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Before("@annotation(TargetDataSource)")
    public void beforeSwitchDS(JoinPoint point){

    //获得当前访问的class
    Class<?> className = point.getTarget().getClass();

    //获得访问的方法名
    String methodName = point.getSignature().getName();
    //得到方法的参数的类型
    Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
    String dataSource = DataSourceContextHolder.DEFAULT_DS;
    try {
    // 得到访问的方法对象
    Method method = className.getMethod(methodName, argClass);

    // 判断是否存在@DS注解
    if (method.isAnnotationPresent(TargetDataSource.class)) {
    TargetDataSource annotation = method.getAnnotation(TargetDataSource.class);
    // 取出注解中的数据源名
    dataSource = annotation.value();
    }
    } catch (Exception e) {
    e.printStackTrace();
    }

    // 切换数据源
    DataSourceContextHolder.setDataSourceType(dataSource);

    }


    @After("@annotation(TargetDataSource)")
    public void afterSwitchDS(JoinPoint point){

    DataSourceContextHolder.clearDataSourceType();

    }

    }











  • 相关阅读:
    使用集合组织相关数据
    引用类型传递 ListView展示数据
    关于ArrayList线程安全解决方案
    Java异常错误的面试题及答案
    希尔排序
    Struts2的简单认识
    新闻发布系统
    了解vo pojo javabean dto
    Spring MVC 笔记及简单了解
    jsp的九大内置对象
  • 原文地址:https://www.cnblogs.com/xues/p/11810199.html
Copyright © 2020-2023  润新知