不一样的多数据源,请查收!

需求:

// 从配置文件中读取多数据源配置,将数据依次读取放入List
// 不需要实体类,用LinkedHashMap来存储每行数据,有序

// 准备:创建3个数据库(test、test1、test2),为了方便测试,在三个数据库中分别建立三个teacher表

包结构
不一样的多数据源,请查收!_第1张图片
不多说,直接上代码

package com.javaboy.datasource;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 数据源配置类
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
public class DataSourceProperties {

    private String url;

    private String driverClassName;

    private String userName;

    private String password;

    // Druid默认参数
    private int initialSize = 2;
    private int maxActive = 10;
    private int minIdle = -1;
    private long maxWait = 60 * 1000L;
    private long timeBetweenEvictionRunsMillis = 60 * 1000L;
    private long minEvictableIdleTimeMillis = 1000L * 60L * 30L;
    private long maxEvictableIdleTimeMillis = 1000L * 60L * 60L * 7;
    private boolean poolPreparedStatements = false;
    private String filters = "stat,wall";
    private int maxPoolPreparedStatementPerConnectionSize = 20;
    private boolean useGlobalDataSourceStat = true;
    private String connectionProperties = "druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500";
}
package com.javaboy.datasource;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 存放从节点数据源
 */
public class DynamicDataSourceProperties {

    private Map<String,DataSourceProperties> datasource = new LinkedHashMap<>();

    public void setDatasource(Map<String,DataSourceProperties> datasource){
        this.datasource = datasource;
    }

    public Map<String,DataSourceProperties> getDatasource(){
        return datasource;
    }
}

package com.javaboy.datasource;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * 读取数据源配置,放入容器
 * 匹配默认数据源
 */
@Configuration
public class DynamicDataSourceConfig {

    // 将默认数据源的属性复制给DataSourceProperties
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSourceProperties dataSourceProperties(){
        return new DataSourceProperties();
    }
    // 将从节点数据源的属性复制给DataSourceProperties

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.dynamic")
    public DynamicDataSourceProperties dynamicDataSourceProperties(){
        return new DynamicDataSourceProperties();
    }

    //配置自定义数据源
    @Bean
    public DynamicDataSource dynamicDataSource(DataSourceProperties dataSourceProperties, DynamicDataSourceProperties dynamicDataSourceproperties) {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();

        //其他数据源
        Map<String, DataSourceProperties> dataSourcePropertiesMap = dynamicDataSourceproperties.getDatasource();
        Map<Object, Object> targetDataSources = new HashMap<>(dataSourcePropertiesMap.size());
        //遍历除主数据源外的其他数据源
        for (Map.Entry<String, DataSourceProperties> properties : dataSourcePropertiesMap.entrySet()) {
            //创建其他数据源
            DruidDataSource druidDataSource = buildDruidDataSource(properties.getValue());
            targetDataSources.put(properties.getKey(), druidDataSource);
        }
        dynamicDataSource.setTargetDataSources(targetDataSources);

        //创建默认数据源
        DruidDataSource defaultDataSource = buildDruidDataSource(dataSourceProperties);
        dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);

        return dynamicDataSource;
    }

    //给druid数据源成员赋值
    public static DruidDataSource buildDruidDataSource(DataSourceProperties properties) {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(properties.getDriverClassName());
        druidDataSource.setUrl(properties.getUrl());
        druidDataSource.setUsername(properties.getUserName());
        druidDataSource.setPassword(properties.getPassword());
        // Druid默认参数
        druidDataSource.setInitialSize(properties.getInitialSize());
        druidDataSource.setMaxActive(properties.getMaxActive());
        druidDataSource.setMinIdle(properties.getMinIdle());
        druidDataSource.setMaxWait(properties.getMaxWait());
        druidDataSource.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRunsMillis());
        druidDataSource.setMinEvictableIdleTimeMillis(properties.getMinEvictableIdleTimeMillis());
        druidDataSource.setMaxEvictableIdleTimeMillis(properties.getMaxEvictableIdleTimeMillis());
        try {
            druidDataSource.setFilters(properties.getFilters());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return druidDataSource;
    }
}
package com.javaboy.datasource;

/**
 * 多数据源上下文
 * 用于存储我们当前线程的数据源key
 */
public class DynamicDataContextHolder {

    /**
     * 线程级别的私有变量
     */
    private static final ThreadLocal<String> HOLDER = new ThreadLocal<>();

    /**
     * 获得当前线程数据源
     */
    public static String get() {
        return HOLDER.get();
    }

    /**
     * 设置当前线程数据源
     */
    public static void set(String dataSourceRouterKey) {
        HOLDER.set(dataSourceRouterKey);
    }

    /**
     * 清空当前线程数据源
     * 设置数据源之前一定要先移除
     */
    public static void remove() {
        HOLDER.remove();
    }
}
package com.javaboy.datasource;

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

/**
 * 动态数据源路由
 * 通知spring用当前key的数据源
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    //返回当前线程的数据源的key
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataContextHolder.get();
    }
}
package com.javaboy.datasource;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

/**
 * 多数据源,切面处理类
 */
@Aspect
@Component
public class DataSourceAspect {

    //用环绕通知执行业务逻辑方法
    @Around("execution(* com.javaboy.service.impl.*.*(..)) && args(key)")
    public Object around(ProceedingJoinPoint point, String key) throws Throwable {
        // 在执行业务方法之前,将数据源配置信息放入线程中
        DynamicDataContextHolder.set(key);
        Object proceed=null;
        try {
            //执行业务逻辑方法并返回
            proceed=point.proceed();
        } catch (Exception e){
            //方法执行异常
            e.printStackTrace();
        }finally {
            //清空当前线程数据源
            DynamicDataContextHolder.remove();
        }
        return proceed;
    }
}

==application.yml

spring:
  datasource: # 默认数据源
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: ****
    password: ****
    driver-class-name: com.mysql.jdbc.Driver
    dynamic:
      datasource: # 从节点数据源
        slave1:
          url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
          username: ****
          password: ****
          driver-class-name: com.mysql.jdbc.Driver
        slave2:
          url: jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
          username: ****
          password: ****
          driver-class-name: com.mysql.jdbc.Driver
        slave3:
          url: jdbc:mysql://localhost:3306/test3?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
          username: ****
          password: ****
          driver-class-name: com.mysql.jdbc.Driver
mybatis:
  mapper-locations: classpath:mapper/*Dao.xml

======DataDao.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.javaboy.dao.DataDao">

    <select id="queryAllData" resultType="java.util.LinkedHashMap" >
	    select * from teacher
    </select>
</mapper>

============DataDao ===============

package com.javaboy.dao;

import java.util.LinkedHashMap;
import java.util.List;

public interface DataDao {
    
    List<LinkedHashMap<String,Object>> queryAllData();

}

package com.javaboy.service.impl;

import com.javaboy.dao.DataDao;
import com.javaboy.service.DataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.LinkedHashMap;
import java.util.List;

@Service
public class DataServiceImpl implements DataService {
    @Autowired
    DataDao dataDao;

    @Override
    public List<LinkedHashMap<String, Object>> queryAllData(String key) {
        return dataDao.queryAllData();
    }
}

====调用接口测试=

package com.javaboy.controller;


import com.javaboy.datasource.DataSourceProperties;
import com.javaboy.datasource.DynamicDataSourceProperties;
import com.javaboy.service.DataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author 马文达
 * @date 2020/5/9 16:45
 */

@RestController
public class DataSourceController {
    @Autowired
    DynamicDataSourceProperties dynamicDataSourceProperties;
    @Autowired
    DataService dataService;

    @GetMapping("/test")
    public String testDataSource(){

        Map<String, DataSourceProperties> datasource = dynamicDataSourceProperties.getDatasource();
        Set<String> strings = datasource.keySet();
        for(String strs:strings){
            List<LinkedHashMap<String, Object>> hashMaps = dataService.queryAllData(strs);
            if(hashMaps==null){break;}
            System.out.println(hashMaps);
        }

        return "200";
    }
}

==结果
不一样的多数据源,请查收!_第2张图片

不断地学习中,有任何问题欢迎下方留言

你可能感兴趣的:(多数据源,MySQL,springboot)