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. VS2013添加重构重命名功能

    VS2015.VS2017都自带重构重命名功能,早年用Eclipse的时候也频繁的使用这一功能,最近发现VS2013没有内置,需要装插件. 下载:https://marketplace.visuals ...

  2. tensorflow用dropout解决over fitting-【老鱼学tensorflow】

    在机器学习中可能会存在过拟合的问题,表现为在训练集上表现很好,但在测试集中表现不如训练集中的那么好. 图中黑色曲线是正常模型,绿色曲线就是overfitting模型.尽管绿色曲线很精确的区分了所有的训 ...

  3. Redis持久化之RDB

    本文及后续文章,Redis版本均是v3.2.8 上篇文章介绍了RDB的优缺点,我们先来回顾下RDB的主要原理,在某个时间点把内存中所有数据保存到磁盘文件中,这个过程既可以通过人工输入命令执行,也可以让 ...

  4. kafka+zookeeper集群

    参考:  kafka中文文档   快速搭建kafka+zookeeper高可用集群   kafka+zookeeper集群搭建 kafka+zookeeper集群部署 kafka集群部署   kafk ...

  5. ScriptEngine执行复杂js报数组越界

    import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineMan ...

  6. notes for lxf(三)

    纯函数式编程是没有变量的,只要输入确定输出就确定 指高度抽象的编程范式 特点 函数本身可以作为参数传入 或者允许返回一个函数 Higher-order function 一个函数可以接收另一个函数作为 ...

  7. 记录以下docker的基本命令

    docker search xxx(tag)      在OFFICIAL上ok的是官方镜像    这里也可以去dockerhub上面看到   搜索xxx镜像docker images查看本地所安装的 ...

  8. Python-第一篇-python初识及变量

    <work smart>主动分享成果和经验,与同伴共同成长</smart work> 启文:使用20多种编程语言,对大家说节日快乐 万国码使用16位(至少)表示内容: ASCI ...

  9. VMware workstation pro 15 安装Ubuntu(图文教程)

    今天分享一下虚拟机安装Ubuntu的过程,在开始安装之前,需要下载VMware workstation pro和Ubuntu镜像,两者我都用的最新版,由于VMware workstation pro ...

  10. 展开被 SpringBoot 玩的日子 《 五 》 spring data jpa 的使用

    在上篇文章< 展开被 SpringBoot 玩的日子 < 二 >WEB >中简单介绍了一下spring data jpa的基础性使用,这篇文章将更加全面的介绍spring da ...