1、原理图

2、创建枚举类

/**
* 存数据源key值
*/
public enum DataSourceKey {
master,salve,migration
}

3、创建自定义注解类

/**
* 自定义注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBSource
{ String value() default "master"; }

4、切换数据源类

/**
* @author yehui
* 根据线程动态切换数据源
*/
@Configuration
public class DynamicDataSourceContextHolder {
private static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class); /**
* 设置默认数据源
*/
public static String DEFAULT_DS = "master";
/**
*用于轮训计数
*/
private static int counter = 0;
/*
* 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
*/
private static final ThreadLocal<String> contextHolder = ThreadLocal.withInitial(() -> DataSourceKey.master.name()); /**
*用于在切换数据源时保证不会被其他线程修改
*/
public static Lock lock = new ReentrantLock(); /**
* 设置数据源
*/
public static void setDB(String dbType){
log.info("切换到{" + dbType + "}数据源");
contextHolder.set(dbType);
} /**
* 得到数据源
*
*/
public static String getDB(){
return contextHolder.get();
} /**
* 使用主数据源
*/
public static void useMasterDataSource() {
contextHolder.set(DataSourceKey.master.name());
}
/**
* 移除数据源
*/
public static void removeDB(){
contextHolder.remove();
}
/**
* The constant slaveDataSourceKeys.
*/
public static List<Object> slaveDataSourceKeys = new ArrayList<>();
/**
* 当使用只读数据源时通过轮循方式选择要使用的数据源
*/
public static String getSlaveDB(){
lock.lock();
try {
int datasourceKeyIndex = counter % slaveDataSourceKeys.size();
counter++;
return String.valueOf(slaveDataSourceKeys.get(datasourceKeyIndex));
} catch (Exception e) {
log.error(e.getMessage(), e);
e.printStackTrace();
return "master";
} finally {
lock.unlock();
}
}
}

5、获取数据源类

/**
* @author yehui
* 多数据源的选择
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final Logger log = LoggerFactory.getLogger(DynamicDataSource.class); @Override
protected Object determineCurrentLookupKey() {
log.info("Current DataSource is " + DynamicDataSourceContextHolder.getDB());
return DynamicDataSourceContextHolder.getDB();
}
}

6、Aop类

/**
* @author yehui
* 自定义注解 + AOP的方式实现数据源动态切换。
*/
@Aspect
@Component
public class DynamicDataSourceAspect {
private static final Logger log = LoggerFactory.getLogger(DynamicDataSourceAspect.class); @Before("@annotation(DBSource)")
public void beforeSwitchDB(JoinPoint joinPoint,DBSource DBSource){
//获取目标类的方法
Class<?> aClass = joinPoint.getTarget().getClass();
//获得访问的方法名
String methodName = joinPoint.getSignature().getName();
//得到方法的参数类型
Class[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
String dataSource = DynamicDataSourceContextHolder.DEFAULT_DS;
try {
Method method = aClass.getMethod(methodName, parameterTypes);
if(method.isAnnotationPresent(DBSource.class)){
DBSource db = method.getAnnotation(DBSource.class);
//指定数据源
dataSource = db.value();
}else{
//轮训设置数据源
dataSource = DynamicDataSourceContextHolder.getSlaveDB();
}
} catch (NoSuchMethodException e) {
log.error(e.getMessage(), e);
}
//设置数据源
DynamicDataSourceContextHolder.setDB(dataSource);
} @After("@annotation(DBSource)")
public void afterSwitchDB(DBSource DBSource){
DynamicDataSourceContextHolder.removeDB();
}
}

6、application.properties文件

spring.druid.datasource.slave.password=root
spring.druid.datasource.slave.username=root
spring.druid.datasource.slave.jdbc-url=jdbc:mysql://localhost:3306/study
spring.druid.datasource.slave.driver-class-name=com.mysql.jdbc.Driver spring.druid.datasource.master.password=root
spring.druid.datasource.master.username=root
spring.druid.datasource.master.jdbc-url=jdbc:mysql://localhost:3306/study01
spring.druid.datasource.master.driver-class-name=com.mysql.jdbc.Driver spring.druid.datasource.migration.password=root
spring.druid.datasource.migration.username=root
#2.0版本多数据源必须是使用jdbc-url 不能使用url,否则报错 jdbcUrl is required with driverClassName
spring.druid.datasource.migration.jdbc-url=jdbc:mysql://localhost:3306/study02
spring.druid.datasource.migration.driver-class-name=com.mysql.jdbc.Driver

7、数据源配置类

/**
* @author yehui
* 数据源配置类
*/
@Configuration
public class DataSourceConfig { /**
* 主数据
*
* @return data source
*/
@Bean("master")
@Primary
@ConfigurationProperties(prefix = "spring.druid.datasource.master")
public DataSource master() {
return DataSourceBuilder.create().build();
} /**
* 从数据库
*
* @return data source
*/
@Bean("slave")
@ConfigurationProperties(prefix ="spring.druid.datasource.slave")
public DataSource slave() {
return DataSourceBuilder.create().build();
}
/**
* 从数据库
*
* @return data source
*/
@Bean("migration")
@ConfigurationProperties(prefix ="spring.druid.datasource.migration")
public DataSource migration() {
return DataSourceBuilder.create().build();
} /**
* 配置动态数据源
*
* @return
*/
@Bean("dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicDataSource dynamicRoutingDataSource = new DynamicDataSource();
Map<Object, Object> dataSourceMap = new HashMap<>(4);
dataSourceMap.put(DataSourceKey.master.name(), master());
dataSourceMap.put(DataSourceKey.salve.name(), slave());
dataSourceMap.put(DataSourceKey.master.name(), slave()); //设置默认的数据源
dynamicRoutingDataSource.setDefaultTargetDataSource(master());
// 多个slave数据源在此添加,自定义key,用于轮询
dataSourceMap.put(DataSourceKey.salve.name() + "1", slave());
//设置目标数据源
dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);
//将数据源的key放在集合中判断是否正常
DynamicDataSourceContextHolder.slaveDataSourceKeys.addAll(dataSourceMap.keySet()); //实现负载均衡算法 将 Slave 数据源的 key 放在集合中,用于轮循
DynamicDataSourceContextHolder.slaveDataSourceKeys.addAll(dataSourceMap.keySet());
DynamicDataSourceContextHolder.slaveDataSourceKeys.remove(DataSourceKey.migration.name());
return dynamicRoutingDataSource;
} /**
* 设置工厂类
*/
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean() {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource()); //此处设置为了解决找不到mapper文件的问题
try {
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*Mapper.xml"));
} catch (IOException e) {
e.printStackTrace();
}
return sqlSessionFactoryBean;
} /**
* 事物管理器
*/
@Bean("transactionManager")
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}
}

8、启动类

/**
* springboot入口类,此类需要在所有用到的package上层 exclude =
* {DataSourceAutoConfiguration.class}
* 禁用springboot默认加载的application.properties单数据源配置
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class StartApp {
public static void main(String[] args) {
SpringApplication.run(StartApp.class);
}
}

9、测试

mapper接口

@Mapper
public interface UserDataSourceMapper {
public List<TbUser> findUser();
}

mapper文件

<?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.yehui.mapper.UserDataSourceMapper">
<select id="findUser" resultType="com.yehui.entity.TbUser">
select * from tb_user
</select>
</mapper>

service类

@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDataSourceMapper userMapper; @Override
@DBSource("slave")//使用数据源打上注解即可
public List<TbUser> findUser() {
return userMapper.findUser();
}
}

controller类

@RestController
public class UserController { @Autowired
private UserService userService;
@RequestMapping("/findUser")
public List<TbUser> findUser(){
return userService.findUser();
}
}

效果:

如图所示,则动态数据源配置成功

SpringBoot动态数据源的更多相关文章

  1. spring boot动态数据源方案

    动态数据源 1.背景 动态数据源在实际的业务场景下需求很多,而且想要沟通多数据库确实需要封装这种工具,针对于bi工具可能涉及到从不同的业务库或者数据仓库中获取数据,动态数据源就更加有意义. 2.依赖 ...

  2. springboot动态多数据源

    参考文章:https://www.cnblogs.com/hehehaha/p/6147096.html 前言 目标是springboot工程支持多个MySQL数据源,在代码层面上,同一个SQL(Ma ...

  3. springboot 双数据源+aop动态切换

    # springboot-double-dataspringboot-double-data 应用场景 项目需要同时连接两个不同的数据库A, B,并且它们都为主从架构,一台写库,多台读库. 多数据源 ...

  4. springboot动态多数据源切换

    application-test.properties #datasource -- mysql multiple.datasource.master.url=jdbc:mysql://localho ...

  5. SpringBoot(十一)-- 动态数据源

    SpringBoot中使用动态数据源可以实现分布式中的分库技术,比如查询用户 就在用户库中查询,查询订单 就在订单库中查询. 一.配置文件application.properties # 默认数据源 ...

  6. SpringBoot和Mycat动态数据源项目整合

    SpringBoot项目整合动态数据源(读写分离) 1.配置多个数据源,根据业务需求访问不同的数据,指定对应的策略:增加,删除,修改操作访问对应数据,查询访问对应数据,不同数据库做好的数据一致性的处理 ...

  7. SpringBoot整合MyBatisPlus配置动态数据源

    目录 SpringBoot整合MyBatisPlus配置动态数据源 SpringBoot整合MyBatisPlus配置动态数据源 推文:2018开源中国最受欢迎的中国软件MyBatis-Plus My ...

  8. SpringBoot集成Mybatis配置动态数据源

    很多人在项目里边都会用到多个数据源,下面记录一次SpringBoot集成Mybatis配置多数据源的过程. pom.xml <?xml version="1.0" encod ...

  9. SpringBoot多数据源动态切换数据源

    1.配置多数据源 spring: datasource: master: password: erp_test@abc url: jdbc:mysql://127.0.0.1:3306/M201911 ...

随机推荐

  1. 《Cracking the Coding Interview》——第2章:链表——题目3

    2014-03-18 02:25 题目:给定一个单链表中间的节点,删掉那个节点. 解法:把后面节点的数据域拷到当前节点来,然后删除后面那个节点.当前节点不是尾巴,所以后面不为空. 代码: // 2.2 ...

  2. Pascal “内存病毒”(骗人的)

    Pascal内存病毒 Chaobs从互联网上获得 pascal病毒虽然说只用Ctrl+Pause Break就可以关闭,但是像有些程序一旦启动,不用等你找到那两个键,就自己运行结束关闭了.比如下面一个 ...

  3. USACO Section2.1 Sorting a Three-Valued Sequence 解题报告

    sort3解题报告 —— icedream61 博客园(转载请注明出处)---------------------------------------------------------------- ...

  4. android的5个进程等级

    一.Foreground Process(前台进程,优先级别最高) 1.正处于 Activity Resume() 状态 2.正处于与 bound 服务交互的状态 3.正处于服务在前台运行的状态(st ...

  5. Python 3基础教程11-如何利用pip命令安装包和模块

    本文介绍如何利用pip命令安装Python相关的包和模块.在Python中有些方法或者模块是自带的功能,也叫(build-in),内构函数,实际使用,可能内构函数或者模块不能完成我们的任务,我们就需要 ...

  6. Django学习笔记(二):使用Template让HTML、CSS参与网页建立

    Django学习笔记(二):使用Template让HTML.CSS参与网页建立 通过本文章实现: 了解Django中Template的使用 让HTML.CSS等参与网页建立 利用静态文件应用网页样式 ...

  7. Linux cooked-mode capture 格式转换

    tcpdump抓包时,如果-i选项指定为一个网卡地址,那么抓取的数据包数据链路层是以太网头部:如果指定any,则以太网头部将被替换为linux cooked capture头部 # tcpdump - ...

  8. 安卓context(一)

    最近看了一下深入安卓内核,毫无安卓基础的我一头深入不可自拔,看的是云里雾里,第一遍看到一半左右似乎开始失去了效率. 现在开始第二遍,并对看过的重要知识点以个人的理解进行梳理(不免有错的地方,好心人请告 ...

  9. windows系统查找文件-通配符的使用

    在windows中可以使用通配符“* ”.“? ”查找文件.对于相同字符开头的单词和相同字符结尾的单词可以用“<”和“ >”通配符查找单词.1.如果要查找: 任意单个字符 :键入 ? 例如 ...

  10. (总结)Linux服务器上最简单的Nginx反向代理配置

    Nginx不但是一款高性能的Web服务器,也是高性能的反向代理服务器.下面简单说说Nginx的反向代理功能. 反向代理是什么? 反向代理指以代理服务器来接受Internet上的连接请求,然后将请求转发 ...