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. [转] Vue中异步错误处理

    一般在一个项目开始之前,我们一般会对现有的框架做一定功能上的丰富,比如对ajax请求功能的二次封装,封装的功能可能包含了:通用错误处理,请求过滤,响应过滤等等.如果我们封装的函数叫request,那么 ...

  2. 简易promise的实现(一)

    code 最近在思考promise的实现原理 于是准备自己写一个简单的demo 一开始想到的问题有两个 1.链式调用 2.异步顺序执行 -------------------------------- ...

  3. 使用Nexus搭建私有Nuget仓库

    前言 Nuget是ASP .NET Gallery的一员,是免费.开源的包管理工具,专注于在.Net / .Net Core应用开发过程中第三方组件库的管理,相对于传统单纯的dll引用要方便.科学得多 ...

  4. 575. Distribute Candies

    https://leetcode.com/problems/distribute-candies/description/ 题目比较长,总结起来很简单:有个整型数组,长度是偶数,把它分成两份,要求有一 ...

  5. Ansible入门篇:playbook的使用

    playbooks介绍 playbooks是 一个不同于使用Ansible命令行执行方式的模式,其功能更强大灵活.简单来说,playbook是一个非常简单的配置管理和多主机部署系统,不同于任何已经存在 ...

  6. 二维条码扫描模组在肯德基KFC的无纸化点餐解决方案

    在如今提倡节约资源的环境下,肯德基在品牌发展中,逐渐实现无纸化点餐,不仅节约了纸质点餐单,而且还具有节约资源的示范作用.而其中二维码扫描模组是这套无纸化点餐方案的重点,在整套设备中,加入二维码扫描模组 ...

  7. 课堂小记---JavaScript(4)

    day11 1.正则表达式 去掉首尾的空格或者其他字符 replace方法可传入函数可分组. 以下为分组 基础正则表达式语法: /** * 正则表达式是一个对象类型 */ // 匹配字符串中的che ...

  8. C语言作业06--结构体&文件

    1.本章学习总结 1.1 思维导图 1.2学习体会 在本周的学习中,我们学习了关于结构体和文件的内容.定义结构体可以使代码整个练习更加紧密,非常实用,当我们需要在对一个个体的不同属性调用时可以更加系统 ...

  9. TextBox使用技巧--转载

    [转载出处注明:http://tieba.baidu.com/p/3677706825] 在使用Visual Basic开发应用程序时,TextBox控件是最常用的(特别对于数据库程序),以下是笔者在 ...

  10. pycharm的list中copy的应用

    #拷贝的意思 li = [11,22,33,44] v = li.copy() print(v) #输出结果 [11,22,33,44] #浅拷贝