springboot中实现多数据源
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中实现多数据源的更多相关文章
- springboot 中使用Druid 数据源提供数据库监控
一.springboot 中注册 Servlet/Filter/Listener 的方式有两种,1 通过代码注册 ServletRegistrationBean. FilterRegistration ...
- springboot(整合多数据源demo,aop,定时任务,异步方法调用,以及获取properties中自定义的变量值)
有这么一个需求 每个部门,需要操作的数据库不同,A部门要将数据放test数据库,B 部门数据 要放在test1数据库 同一个项目 需要整合 多个数据源 上传个demo 方便自己以后回看!!!!!!!! ...
- springboot中有用的几个有用aware以及bean操作和数据源操作
本文参考了: https://blog.csdn.net/derrantcm/article/details/76652951 https://blog.csdn.net/derrantcm/arti ...
- SpringBoot+MyBatis配置多数据源
SpringBoot 可以支持多数据源,这是一个非常值得学习的功能,但是从现在主流的微服务的架构模式中,每个应用都具有唯一且准确的功能,多数据源的需求很难用到,考虑到实际情况远远比理论复杂的多,这里还 ...
- springboot mybatis 使用多数据源
SpringBoot系列博客目录,含1.5.X版本和2.X版本 springboot2.0正式版发布之后,很多的组件集成需要变更了,这次将多数据源的使用踩的坑给大家填一填.当前多数据源的主要为主从库, ...
- SpringBoot整合Mybatis多数据源 (AOP+注解)
SpringBoot整合Mybatis多数据源 (AOP+注解) 1.pom.xml文件(开发用的JDK 10) <?xml version="1.0" encoding=& ...
- SpringBoot中使用hikariCP
本篇文章主要实现SpringBoot中使用hikariCP: 一 .使用工具 1. JDK1.8 2. springToolSuit(STS) 3. maven 二.创建项目 1.首先创建一个Spri ...
- SpringBoot和Mycat动态数据源项目整合
SpringBoot项目整合动态数据源(读写分离) 1.配置多个数据源,根据业务需求访问不同的数据,指定对应的策略:增加,删除,修改操作访问对应数据,查询访问对应数据,不同数据库做好的数据一致性的处理 ...
- spring扩展点之四:Spring Aware容器感知技术,BeanNameAware和BeanFactoryAware接口,springboot中的EnvironmentAware
aware:英 [əˈweə(r)] 美 [əˈwer] adj.意识到的;知道的;觉察到的 XXXAware在spring里表示对XXX感知,实现XXXAware接口,并通过实现对应的set-XXX ...
随机推荐
- C# 知识点回忆..
方便查阅: 数据结构与算法 1.线性表: (1)数据结构2 - 线性表 (2)数据结构和算法 c#– 1.单项链表 委托和事件 委托1:C#4.0图解教程 - 第15章 委托 委托2:<C#本质 ...
- C# DynamicObject 动态对象
dynamic是FrameWork4.0的新特性.dynamic的出现让C#具有了弱语言类型的特性.编译器在编译的时候不再对类型进行检查,编译期默认dynamic对象支持你想要的任何特性.比如,即使你 ...
- java解析json的操作
import java.io.FileNotFoundException; import java.io.FileReader; import com.google.gson.JsonArray; i ...
- tensorflow用dropout解决over fitting-【老鱼学tensorflow】
在机器学习中可能会存在过拟合的问题,表现为在训练集上表现很好,但在测试集中表现不如训练集中的那么好. 图中黑色曲线是正常模型,绿色曲线就是overfitting模型.尽管绿色曲线很精确的区分了所有的训 ...
- mxGraph绘制流程图
代码如下: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w ...
- toString
在java中使用toString: 如果在Java在输出定义一个Person类 然后实例化person per 直接用system.out.println(per);无法得到我们想要的实例化内容 p ...
- Mysql更新关联子查询报错
报错内容:sql 1093 - You can't specify target table 'u' for update in FROM clause 错误原因: if you're doing ...
- OI暑假集训游记
莞中OI集训游记 Written BY Jum Leon. I 又是一载夏,本蒟蒻以特长生考入莞中,怀着忐忑的心情到了8月,是集训之际.怀着对算法学习的向往心情被大佬暴虐的一丝恐惧来到了 ...
- c# asp.net mvc使用斑马GK888t打印机打印标签
前言 c#语言,asp.net mvc,南京都昌电子病历模板工具(类似word),斑马GK888t,打印手腕带和标签纸. 实现步骤为:在页面上显示一个或多个都昌模板工具,点击页面上的button,出现 ...
- 原生JS面试题
面试中遇到的原生js题总结 1.js 去重1) indexOf Array.prototype.unique = function(){ var result = []; var len = th ...