范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

SpringBoot多数据源切换(二)(依旧超级简单)

  背景:主从架构下,数据库的读写分离1. 依赖                          org.springframework.boot             spring-boot-starter-web                               org.projectlombok             lombok             true                               org.springframework.boot             spring-boot-starter-test             test                               com.baomidou             mybatis-plus-boot-starter             3.5.3                               org.springframework.boot             spring-boot-starter-aop                               com.alibaba             druid-spring-boot-starter             1.2.16                               mysql             mysql-connector-java             8.0.29               2.配置数据源spring:   datasource:     druid:       type: com.alibaba.druid.pool.DruidDataSource       master:         url: jdbc:mysql://127.0.0.1:3307/user1?useUnicode=true&characterEncoding=utf8&useSSL=false         username: root         password: root         driver-class-name: com.mysql.cj.jdbc.Driver       slave1:         enabled: true         url: jdbc:mysql://127.0.0.1:3308/user1?useUnicode=true&characterEncoding=utf8&useSSL=false         username: root         password: root         driver-class-name: com.mysql.cj.jdbc.Driver       otmstariff:         enabled: false         url: jdbc:mysql://127.0.0.1:3306/user1?useUnicode=true&characterEncoding=utf8&useSSL=false         username: root         password: root         driver-class-name: com.mysql.cj.jdbc.Driver 3. 注册数据源
  1)创建一个数据源枚举类  public enum DataSourceType {     /**      * 主库      */     MASTER,      /**      * 从库      */     SLAVE1,      SLAVE2 }
  2)我们切换数据库所需要的bean全部交给spring容器中  @Configuration public class DynamicDataSourceConfig {      @Bean     @Qualifier("masterDataSource")     @ConfigurationProperties("spring.datasource.druid.master")     public DataSource masterDataSource() {         return DruidDataSourceBuilder.create().build();     }      @Qualifier("slave1DataSource")     @Bean     @ConfigurationProperties("spring.datasource.druid.slave1")     // 根据配置文件enabled属性,判断该配置是否生效     @ConditionalOnProperty(prefix = "spring.datasource.druid.slave1", name = "enabled", havingValue = "true")     public DataSource slave1DataSource() {         return DruidDataSourceBuilder.create().build();     }      @Qualifier("slave2DataSource")     @Bean     @ConfigurationProperties("spring.datasource.druid.slave2")     @ConditionalOnProperty(prefix = "spring.datasource.druid.slave2", name = "enabled", havingValue = "true")     public DataSource slave2DataSource() {         return DruidDataSourceBuilder.create().build();     }        @Bean(name = "dynamicDataSource")     @Primary     public DynamicDataSource dataSource(DataSource masterDataSource) {         Map targetDataSources = new HashMap<>();         targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);         setDataSource(targetDataSources, DataSourceType.SLAVE1.name(), "slave1DataSource");         setDataSource(targetDataSources, DataSourceType.SLAVE2.name(), "slave2DataSource");         DynamicDataSource dynamicDataSource = new DynamicDataSource();         dynamicDataSource.setTargetDataSources(targetDataSources);         dynamicDataSource.setDefaultTargetDataSource(masterDataSource);         return dynamicDataSource;     }      /**      * 设置数据源      *      * @param targetDataSources 备选数据源集合      * @param sourceName 数据源名称      * @param beanName bean名称      */     public void setDataSource(Map targetDataSources, String sourceName, String beanName)     {         try         {             DataSource dataSource = SpringUtils.getBean(beanName);             targetDataSources.put(sourceName, dataSource);         }         catch (Exception e)         {         }     }   }  4.切换数据源public class DynamicDataSourceContextHolder {     // 线程安全     private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); 	/**      * 设置数据源变量      * @param dataSourceEnum 数据源变量      */     public static void setDataSourceType(String type) {         CONTEXT_HOLDER.set(type);     } 	/**      * 获取数据源变量      * @return 数据源变量      */     public static String getDataSourceType() {         return CONTEXT_HOLDER.get();     } 	/**      * 清理数据源      * @return 数据源变量      */     public static void clearDataSourceType() {         CONTEXT_HOLDER.remove();     } }  5.设置数据源
  新建DynamicDataSource类继承AbstractRoutingDataSource类,并实现determineCurrentLookupKey方法,该方法是指定当前默认数据源的方法,该类是实现动态切换数据源的关键  public class DynamicDataSource extends AbstractRoutingDataSource {      @Override     protected Object determineCurrentLookupKey() {         return DynamicDataSourceContextHolder.getDataSourceType();     } } 6. 自定义多数据源切换注解@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource {     DataSourceType value() default DataSourceType.MASTER; }  7. AOP拦截器的实现@Slf4j @Aspect @Component public class DataSourceAspect {      @Pointcut("@annotation(com.example.datasourceprimordialdemo2.datasource.annotation.DataSource)")     public void doPointCut() {     }      @Around("doPointCut()")     public Object around(ProceedingJoinPoint pointcut) throws Throwable {         MethodSignature signature = (MethodSignature) pointcut.getSignature();         Method method = signature.getMethod();         DataSource dataSource = method.getAnnotation(DataSource.class);         if (Objects.nonNull(dataSource)) {             DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());         }         try {             return pointcut.proceed();         } finally {             // 销毁数据源 在执行方法之后             DynamicDataSourceContextHolder.clearDataSourceType();         }     } } 8. 启动类修改@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 9. 使用
  此处为了测试,直接放在controller使用      @GetMapping("/0")     @DataSource(DataSourceType.MASTER)     public ResponseEntity> query() {         return ResponseEntity.ok(this.userService.query());     }      @GetMapping("/1")     @DataSource(DataSourceType.SLAVE1)     public ResponseEntity> query2() {         return ResponseEntity.ok(this.userService.query());     }      @GetMapping("/2")     @DataSource(DataSourceType.SLAVE2)     public ResponseEntity> query3() {         return ResponseEntity.ok(this.userService.query());     } 为了区分数据不一样,数据库未做主从同步
  master的数据
  slave1的数据
  slave2的数据
  5.用postman进行测试
  获取master的数据
  获取slave1的数据
  获取slave2的数据
  完成~~~源码: [gitee](https://gitee.com/TZWw/datasource-primordial-demo2) [github](https://github.com/1137854811/datasource-primordial-demo2)
  注: 为什么配置了三个数据源,是为了展示我在做的过程中遇到的一个问题
  刚开始我是按照网上查到的方式注册数据源
  这样做,在全部数据源都注入的时候没有问题,当我在配置中心停掉其中一个数据源时就会出现问题
  3)问题(在masterDataSource添加@Primary又会出现其他的错误)  Parameter 1 of method dataSource in com.example.datasourceprimordialdemo2.datasource.config.DynamicDataSourceConfig required a single bean, but 2 were found: 	- masterDataSource: defined by method "masterDataSource" in class path resource [com/example/datasourceprimordialdemo2/datasource/config/DynamicDataSourceConfig.class] 	- slave2DataSource: defined by method "slave2DataSource" in class path resource [com/example/datasourceprimordialdemo2/datasource/config/DynamicDataSourceConfig.class] Action: Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
  4.解决办法(此方式只针对我代码的解决办法,可能会有其他问题导致 此报错,请再寻找其他方法)
  大佬们如果有其他方式请在评论区告知,万分感谢
  我是Tz ,想把我遇到的问题都分享给你,想看更多精彩内容,请关注我的wx公众号zhuangtian

米粉又遭背刺了?小米突然公布千元神机新款处理器换新!昨天小米官方已经宣布将在12月27日这天正式发布米粉备受期待的红米K60系列,这次的红米K60系列共有三款,分别是红米K60e,红米K60和红米K60Pro,这三款机型搭载的处理器西云数据运营亚马逊云科技中国(宁夏)区域五周年在广袤西部见证中国云服务市场飞速发展中国发展网记者成静日前,宁夏西云数据科技有限公司正式迎来运营亚马逊云科技中国(宁夏)区域五周年的日子。中国信息通信研究院(信通院)的数据显示,2017年中国云服务(IaaSPaaSiQOOneo7竞速版配置曝光,使用骁龙8处理器,120瓦的快充iQOOneo7竞速版的配置完全曝光,基本上就是换了处理器,其余配置没有变化的思路。使用骁龙8处理器,这个处理器说句实话,现在相对有点落后,这说明骁龙8最近是有库存的,所以出来一些一个人,真的很穷没钱的样子文夏莫01卷首语贫穷,就像一把枷锁,把一个人禁锢在狭小的圈子里,无法令人得到更好的发展。莎士比亚说钱是一根伟大的魔杖,随随便便就能改变一个人的模样。人生路上,拥有金钱,能让人活得自涂着烈焰红唇,张扬高傲的样子,让人难免起了一种征服欲望因为顾念发现,在晚礼服之下,自己那微微凸起的小腹就格外明显!于是她迅速的把晚礼服换下,又在柜子里翻找了一阵,才找出一条黑色及踝的一字肩长裙。长裙是高腰的,面料垂坠感十足,总算勉强遮迷失沉寂于虚妄,你有多久远离真实纯粹的幸福?闭上你的眼睛,感受迎面而来的微风,站在上顶的最高处,你是否找到了那个答案?我现在头脑一片混乱,不知道未来该如何去做,这样的日子继续下去,连我自己都无法在生命的终点给个痛快的说法你的通讯Plus测评一拍即清晰,各种场景轻松出片这才是移动影像该有的样子视频加载中经典的红圈镜头设计,35mm定制光学系统,第二代骁龙8移动平台12月19日,努比亚正式对外发布了新一代影像性能旗舰手机努比亚Z50。本次,封面新闻也在第一时间拿到了这款被抄书第一天,赶上圣诞节!首先祝大家圣诞节快乐!今天是我抄书的第一天,不知道会不会赚钱,起码是疫情在家躺平期间,终于找到了自己喜欢做的事情!下面文章,选自王小波一只特立独行的猪中的第一个章节里的最后两段我很NBA圣诞大战将一触即发!圣诞节通常充满了节日的欢呼礼物,最重要的是,还有篮球。纽约尼克斯队vs费城76人队几周前,没有人会想到76人队和尼克斯队会成为NBA最热门的球队之一,进入圣诞节展示。然而,我们到了一组让人目眩神迷的北极光图片生活科学杂志在这些令人惊叹的北极光图像中,极光将天空描绘成怪异的绿色和蓝色色调。当夜晚越来越长,白天越来越凉爽时,最北纬和最南纬的天空可能会亮起绿色和蓝色。这些极光,也称为北极光,发生在从太阳红魔8Pro系列将搭载REDMAGICOS6。0支持双开游戏空间等功能IT之家12月25日消息,红魔8Pro系列电竞旗舰将于12月26日1500发布。红魔游戏手机官方今日带来了红魔8Pro系列的最新预热信息,确认新机搭载REDMAGICOS6。0。红
七一文学公交车上的美好时光有一段时间,我常乘坐我们小城的50路公交车,车上的人来来往往,让我想起一句话铁打的公交,流水的乘客。在清晨清新的空气里看车窗外急匆匆的人流,暮色降临时欣赏街上闪烁的霓虹灯,一天的喧七一文学陪父亲散步父亲住院,我去照顾他。守着浅浅入睡的父亲,我的目光一刻也没有离开过他那苍白的脸。那些记录岁月的纹路像一棵老树,枝枝杈杈,触动了我内心最柔软的地方。父亲醒来时,泪水在我的眼眶里打转,按月申报小规模纳税人1月份剔除转让商铺收入后销售额在10万元以下,能否享受免征增值税政策?问我公司是按月申报的增值税小规模纳税人,2023年1月6日转让一间商铺,剔除转让商铺的销售额后,预计1月份销售额在10万元以下,全部开具增值税普通发票,请问我公司可以享受免征增值税窗口看经济发展丨高新区政务服务中心一窗受理快起来,一次服务跑起来视频加载中大众网海报新闻记者程裕涵见习记者厉彦胜日照报道走进高新区政务服务中心,便捷高效的政务服务体验感无处不在。这里进驻了高新区所有的行政许可事项,设置了34个一窗受理综合服务窗代表委员履职记丨全国人大代表陈影下足绣花功夫聚力有效衔接两年前,从北京人民大会堂捧回全国脱贫攻坚先进个人的奖牌后,安徽省淮北市濉溪县刘桥镇扶贫站站长陈影直接接过了乡村振兴的担子。陈影到农户家指导产业发展干了4年多脱贫攻坚,眼看着17个村周小川未来养老保障需个人养老金加以支持配合中证网讯(记者张佳琳)2月25日,博鳌亚洲论坛副理事长周小川在第五届全球财富管理论坛经济重构中的财富管理态势上指出,根据现有趋势,未来国家统筹养老金的水平较为基本,需要个人账户养老阳春市双滘镇发展沙姜产业,走出特色增收致富路时下正是沙姜收获季节,近日,在阳春市双滘镇黄沙村,从绿葱葱的姜地里远远望去,一垄垄沙姜长势良好丰收在望。村民们正在挖姜去泥挑拣剪杆装袋,路边不时过来些车辆,把成堆的沙姜运到村里或者周小川未来养老保障需个人养老金加以支持配合张佳琳中国证券报中证网中证网讯(记者张佳琳)2月25日,博鳌亚洲论坛副理事长周小川在第五届全球财富管理论坛经济重构中的财富管理态势上指出,根据现有趋势,未来国家统筹养老金的水平较为写意中国探寻汉字起源河南漯河许慎文化园走进字圣故里探寻汉字魅力视频加载中汉字是中华文明的载体,是中华文化不可或缺的组成部分。汉字历经数千年的历史变迁,甲骨文金文小篆等古文字与隶书楷书等今文字,在字形与构造意图上存在很大差异。古老文字与后世文字德勤中国消费者对电动汽车的需求呈现刚性本报记者张硕北京报道近期德勤发布全球汽车消费者调研2023报告,报告显示,中国消费者对纯电动汽车的兴趣持续增长,电动车的吸引力主要集中在消费者渴望得到更好的驾驶体验以及燃料成本的大新时代双拥实践特色双拥助力乡风文明建设原标题特色双拥助力乡风文明建设广西崇左市双拥工作领导小组组长蓝晓广西崇左有座红军楼,红军楼前有两棵柏树,都是邓小平同志当年指挥广西左江地区革命斗争和军事行动期间,在楼前栽种的。如今