需求:
// 从配置文件中读取多数据源配置,将数据依次读取放入List
// 不需要实体类,用LinkedHashMap来存储每行数据,有序
// 准备:创建3个数据库(test、test1、test2),为了方便测试,在三个数据库中分别建立三个teacher表
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";
}
}
不断地学习中,有任何问题欢迎下方留言