springboot中实现多数据源

1、什么场景需要多数据源

  • 业务读写分离
  • 业务分库
  • 业务功能模块拆分多库

2、常见的多数据源的方案

  • 按照数据源分别把mapper和entity放到不同的package下,然后用两个数据源分别注册、扫描对应的package,独立的sessionfactoty
  • 基于aop动态的切换的数据源

3、本文重点介绍的是基于aop的方案

3.1、原理介绍

  • DatabaseType列出所有的数据源的key---key
  • DatabaseContextHolder是一个线程安全的DatabaseType容器,并提供了向其中设置和获取DatabaseType的方法
  • DynamicDataSource继承AbstractRoutingDataSource并重写其中的方法determineCurrentLookupKey(),在该方法中使用DatabaseContextHolder获取当前线程的DatabaseType
  • MyBatisConfig中生成2个数据源DataSource的bean---value
  • MyBatisConfig中将1)和4)组成的key-value对写入到DynamicDataSource动态数据源的targetDataSources属性(当然,同时也会设置2个数据源其中的一个为DynamicDataSource的defaultTargetDataSource属性中)
  • 将DynamicDataSource作为primary数据源注入到SqlSessionFactory的dataSource属性中去,并且该dataSource作为transactionManager的入参来构造DataSourceTransactionManager
  • 使用的时候,在dao层或service层先使用DatabaseContextHolder设置将要使用的数据源key,然后再调用mapper层进行相应的操作,建议放在dao层去做(当然也可以使用spring aop+自定注解去做)
  • 注意:在mapper层进行操作的时候,会先调用determineCurrentLookupKey()方法获取一个数据源(获取数据源:先根据设置去targetDataSources中去找,若没有,则选择defaultTargetDataSource),之后在进行数据库操作。

3.2、代码示例

a、配置文件
spring.aop.proxy-target-class = true
spring.aop.auto = true
spring.datasource.druid.db1.url =
spring.datasource.druid.db1.username =
spring.datasource.druid.db1.password =
spring.datasource.druid.db1.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.druid.db1.initialSize = 5
spring.datasource.druid.db1.minIdle = 5
spring.datasource.druid.db1.maxActive = 20
spring.datasource.druid.db2.url =
spring.datasource.druid.db2.username =
spring.datasource.druid.db2.password =
spring.datasource.druid.db2.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.druid.db2.initialSize = 5
spring.datasource.druid.db2.minIdle = 5
spring.datasource.druid.db2.maxActive = 20
spring.datasource.druid.db3.url =
spring.datasource.druid.db3.username =
spring.datasource.druid.db3.password =
spring.datasource.druid.db3.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.druid.db3.initialSize = 5
spring.datasource.druid.db3.minIdle = 5
spring.datasource.druid.db3.maxActive = 20
b、生成Datasource
@Bean(name = "db1")
@ConfigurationProperties(prefix = "spring.datasource.druid.db1")
public DataSource db1() {
return DruidDataSourceBuilder.create().build();
} @Bean(name = "db2")
@ConfigurationProperties(prefix = "spring.datasource.druid.db2")
public DataSource db2() {
return DruidDataSourceBuilder.create().build();
} @Bean(name = "db3")
@ConfigurationProperties(prefix = "spring.datasource.druid.db3")
public DataSource db3() {
return DruidDataSourceBuilder.create().build();
}
c、定义数据源的key
@Getter
@AllArgsConstructor
public enum DBTypeEnum {
db1("db1"),
db2("db2"),
db3("db3");
private String value;
}
d、构造数据源和sessionFactory
/**
* 动态数据源配置
*
* @return
*/
@Bean
@Primary
public DataSource multipleDataSource(
@Qualifier("db1") DataSource db1,
@Qualifier("db2") DataSource db2,
@Qualifier("db3") DataSource db3) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DBTypeEnum.db1.getValue(), db1);
targetDataSources.put(DBTypeEnum.db2.getValue(), db2);
targetDataSources.put(DBTypeEnum.db3.getValue(), db3);
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(db2);
return dynamicDataSource;
} @Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(multipleDataSource(db1(), db2(), db3())); MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCacheEnabled(false);
sqlSessionFactory.setConfiguration(configuration);
// PerformanceInterceptor(),OptimisticLockerInterceptor()
// 添加分页功能
sqlSessionFactory.setPlugins(new Interceptor[] {paginationInterceptor()});
sqlSessionFactory.setGlobalConfig(globalConfiguration());
return sqlSessionFactory.getObject();
}
e、重写datasource切换策略
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDbType();
}
}
f、保存数据源切换的上下文信息
public class DbContextHolder {

  private static final ThreadLocal contextHolder = new ThreadLocal<>();
/**
* 设置数据源
*
* @param dbTypeEnum
*/
public static void setDbType(DBTypeEnum dbTypeEnum) {
contextHolder.set(dbTypeEnum.getValue());
} /**
* 取得当前数据源
*
* @return
*/
public static String getDbType() {
return (String) contextHolder.get();
} /** 清除上下文数据 */
public static void clearDbType() {
contextHolder.remove();
}
}
g、aop实现动态的数据源切换
@Component
@Order(value = -100)
@Slf4j
@Aspect
public class DataSourceSwitchAspect { @Pointcut("execution(* top.zhuofan.datafly.mapper.db1..*.*(..))")
private void db1Aspect() {} @Pointcut("execution(* top.zhuofan.datafly.mapper.db2..*.*(..))")
private void db2Aspect() {} @Pointcut("execution(* top.zhuofan.datafly.mapper.db3..*.*(..))")
private void db3Aspect() {} @Before("db1Aspect()")
public void db1() {
log.debug("切换到db1 数据源...");
DbContextHolder.setDbType(DBTypeEnum.db1);
} @Before("db2Aspect()")
public void db2() {
log.debug("切换到db2 数据源...");
DbContextHolder.setDbType(DBTypeEnum.db2);
} @Before("db3Aspect()")
public void db3() {
log.debug("切换到db3 数据源...");
DbContextHolder.setDbType(DBTypeEnum.db3);
}
}

4、后续

更多精彩,敬请关注, 程序员导航网 https://chenzhuofan.top

springboot中实现多数据源的更多相关文章

  1. springboot 中使用Druid 数据源提供数据库监控

    一.springboot 中注册 Servlet/Filter/Listener 的方式有两种,1 通过代码注册 ServletRegistrationBean. FilterRegistration ...

  2. springboot(整合多数据源demo,aop,定时任务,异步方法调用,以及获取properties中自定义的变量值)

    有这么一个需求 每个部门,需要操作的数据库不同,A部门要将数据放test数据库,B 部门数据 要放在test1数据库 同一个项目 需要整合 多个数据源 上传个demo 方便自己以后回看!!!!!!!! ...

  3. springboot中有用的几个有用aware以及bean操作和数据源操作

    本文参考了: https://blog.csdn.net/derrantcm/article/details/76652951 https://blog.csdn.net/derrantcm/arti ...

  4. SpringBoot+MyBatis配置多数据源

    SpringBoot 可以支持多数据源,这是一个非常值得学习的功能,但是从现在主流的微服务的架构模式中,每个应用都具有唯一且准确的功能,多数据源的需求很难用到,考虑到实际情况远远比理论复杂的多,这里还 ...

  5. springboot mybatis 使用多数据源

    SpringBoot系列博客目录,含1.5.X版本和2.X版本 springboot2.0正式版发布之后,很多的组件集成需要变更了,这次将多数据源的使用踩的坑给大家填一填.当前多数据源的主要为主从库, ...

  6. SpringBoot整合Mybatis多数据源 (AOP+注解)

    SpringBoot整合Mybatis多数据源 (AOP+注解) 1.pom.xml文件(开发用的JDK 10) <?xml version="1.0" encoding=& ...

  7. SpringBoot中使用hikariCP

    本篇文章主要实现SpringBoot中使用hikariCP: 一 .使用工具 1. JDK1.8 2. springToolSuit(STS) 3. maven 二.创建项目 1.首先创建一个Spri ...

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

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

  9. spring扩展点之四:Spring Aware容器感知技术,BeanNameAware和BeanFactoryAware接口,springboot中的EnvironmentAware

    aware:英 [əˈweə(r)] 美 [əˈwer] adj.意识到的;知道的;觉察到的 XXXAware在spring里表示对XXX感知,实现XXXAware接口,并通过实现对应的set-XXX ...

随机推荐

  1. python设计模式---行为型之观察者模式

    比较常用咯~~ from django.test import TestCase from abc import ABCMeta, abstractmethod # 行为型设计模式---观察者模式 c ...

  2. 记一次WordPress 安装的过程

    安装WordPress你我他大家都会,记得10年的时候,哥已经玩转WordPress.dedecms.sns,那为何现在要记一次WordPress安装过程呢? 因为现在不会了! 之前安装都是在Wind ...

  3. get_k_data 接口文档 全新的免费行情数据接口

    get_k_data 接口文档 全新的免费行情数据接口 原创: Jimmy 挖地兔 2016-11-06 前言在tushareAPI里,曾经被用户喜欢和作为典范使用的API get_hist_data ...

  4. 关于WEB-INF目录下的静态资源(js、css、img)的访问

    首先,需要明确的是WEB-INF目录是被保护起来的,其下的jsp页面不能直接运行,只能通过控制器跳转来访问:而同样在此目录下的静态资源(js.css.img)也不能被WEB-INF目录外的其他文件直接 ...

  5. 031 一次全面的java复习

    一:相关概念 1.面向对象的三个特征 封装,继承,多态,这个应该是人人皆知,有时候也会加上抽象. 2.多态的好处 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性.简单的说 ...

  6. symfony简单的博客练习,熟悉具体开发流程

    这里搭建一个简单的博客系统作为练习,之后再完成学校任务搭建一个表白墙, 使用htmlpurifier和parsedown来搭建前端,所以需要先安装这两个第三方包,必须要弄一个composer的国内镜像 ...

  7. 福州大学软件工程1916|W班 第6次作业成绩排名

    作业链接 团队第三次-项目原型设计 评分细则 博客评分标准 在随笔开头,备注小组同学的学号.(1') 文字准确.样式清晰.图文并茂.字数在1000字左右.(10') 原型模型必须采用专用的原型模型设计 ...

  8. 第六章 对象-javaScript权威指南第六版(三)

    6.3 删除内容 delete运算符可以删除对象的属性. delete运算符只能删除自有属性,不能删除继承属性. delete表达式删除成功或没有任何副作用时,它返回true. 6.4 检测属性 用i ...

  9. UWB DWM1000 跟随小车原理---一张图演示

    更多内容参考论坛:bphero.com.cn

  10. python用类实现xrange

    class xrange(object): def __init__(self, start, end=0, step=1): self.start = start self.end = end se ...