充电桩项目实战:搞定多数据源!

你好,我是田哥

最近,我在对充电桩项目进行微服务升级中,既然是项目升级,难免会遇到各种各样的问题。比如:分布式事务问题、多数据源问题、分布式锁问题等。

43b8c38f58ee753cbcea123d0ea2a30d.jpeg

项目技术栈

  • Spring

  • Spring Boot

  • Spring Cloud Alibaba(Nacos、Gateway、openfeigin、Sentinel)

  • MongoDB+Redis

  • EMQX

  • XXL-JOB

  • RabbitMQ

  • MySQL

  • Atomikos(分布式事务)

  • OSS

项目结构

bf6aebf1f57dbda8de8074b0f4f539e4.png
项目结构

题外话:如果想年后找到更好的工作,推荐看这篇文章

Java后端面试复习规划表,5万字

因为对数据库进行拆分成了多个库,所以,肯定会涉及到比如分布式事务、多数据源等问题,关于分布式事务这采用Atomikos解决的,可以参考之前的文章:

Spring Boot+MyBatis+Atomikos+MySQL(附源码)

分布式事务这里就不聊了,咱们来聊聊多数据源的问题。

多数据源

多数据源的场景通常有:

  • 1:主和从数据库数据源

  • 2:A项目中的数据库和B项目中的数据库

  • 3:A公司数据库和B公司数据库

主和从数据库数据源

主要是用于数据库架构变成了主从结构,通常会使用到注解:@Primary

在Spring框架中,@Primary注解用于指定一个Bean作为主要的候选者,当有多个相同类型的Bean可供选择时,标记为@Primary的Bean将优先被考虑。这在处理多个相同类型Bean的情况时非常有用,特别是在自动装配(Autowiring)时。

例如,假设您有一个接口MyService和两个实现类FirstServiceSecondService,并且都使用@Service注解进行了声明。如果没有使用@Primary注解,在进行自动装配时,Spring会抛出异常,因为无法确定应该选择哪个实现类。但是,如果其中一个实现类使用了@Primary注解,那么Spring就会选择这个Bean进行装配。

以下是一个示例:

@Service
public class FirstService implements MyService {// ...
}@Service
@Primary
public class SecondService implements MyService {// ...
}

在上面的代码中,由于SecondService使用了@Primary注解,因此Spring会自动装配SecondService作为MyService的实现类。

A项目中的数据库和B项目中的数据库

我的充电桩项目中就是这类场景,主要是对充电桩项目拆分了。

下面来看看实现过程。

实现

实现通常分为下面几步:

  • pom配置依赖

  • 配置数据源信息

  • 读取配置信息

  • 使用

pom配置依赖
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version>
</dependency>

跟普通Spring Boot项目集成MyBatis没什么区别。

properties配置
spring.datasource.chargeuser.driverClassName = com.mysql.jdbc.Driver
spring.datasource.chargeuser.jdbc-url = jdbc:mysql://localhost:3306/charge-user?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
spring.datasource.chargeuser.username = root
spring.datasource.chargeuser.password = 123456spring.datasource.chargemarket.driverClassName = com.mysql.jdbc.Driver
spring.datasource.chargemarket.jdbc-url = jdbc:mysql://localhost:3306/charge-market?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
spring.datasource.chargemarket.username = root
spring.datasource.chargemarket.password = 123456

我们这里配置了两个数据源,如果有需要我们可以照着这样配置即可。

数据源信息的装配
@Configuration
@MapperScan(basePackages = "com.tian.mapper.market", sqlSessionTemplateRef  = "marketSqlSessionTemplate")
public class DataSourceMarketConfig {@Bean(name = "marketDataSource")@ConfigurationProperties(prefix = "spring.datasource.chargemarket")public DataSource marketDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "marketSqlSessionFactory")public SqlSessionFactory marketSqlSessionFactory(@Qualifier("marketDataSource") DataSource dataSource) throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/market/*.xml"));return bean.getObject();}@Bean(name = "marketTransactionManager")public DataSourceTransactionManager marketTransactionManager(@Qualifier("marketDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Bean(name = "marketSqlSessionTemplate")public SqlSessionTemplate marketSqlSessionTemplate(@Qualifier("marketSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}}

注意:

  • 1:spring.datasource.chargemarket就是我们在properties文件配置数据源信息。

  • 2:com.tian.mapper.market 就是我们需要扫描的mapper

  • 3:classpath:mapper/market/*.xml 扫描的XxxxMapper.xml文件

然后,关于数据源spring.datasource.chargemarket 就这样搞定了,其他mapper的使用和普通mybatis没什么区别。

再来看看spring.datasource.chargeuser数据源的处理,和上面完全一毛一样。

@Configuration
@MapperScan(basePackages = "com.tian.mapper.user", sqlSessionTemplateRef = "userSqlSessionTemplate")
public class DataSourceUserConfig {@Bean(name = "userDataSource")@ConfigurationProperties(prefix = "spring.datasource.chargeuser")public DataSource userDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "userSqlSessionFactory")public SqlSessionFactory userSqlSessionFactory(@Qualifier("userDataSource") DataSource dataSource) throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/user/*.xml"));return bean.getObject();}@Bean(name = "userTransactionManager")public DataSourceTransactionManager userTransactionManager(@Qualifier("userDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Bean(name = "userSqlSessionTemplate")public SqlSessionTemplate userSqlSessionTemplate(@Qualifier("userSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}
}

强调一下:项目中使用UserMapper方式并没有什么区别,还是以前Spring Boot+MyBatis方式,所以这里就没有必要在展示相关无用的代码了。

多数据源配置就这么搞定了,学会(废)了吗?

总结

对上面多数据源的配置多一个简单的总结:

  • 1:数据库连接信息不一样(多数据源)

  • 2:扫描的mapper不一样和mapper.xml

  • 3:然后把对应的dataSourceSqlSessionFactoryTransactionManager以及SqlSessionTemplate关联起来。

最后在使用我们的XxxMapper时候就会自动给我们关联起来了相关的SqlSessionFactoryTransactionManager以及SqlSessionTemplat

回复77,免费获取《面试小抄》

推荐

MySQL 开发规范,非常详细,建议收藏!

16k面试中的10个问题

从0开始搭建公司技术栈,yyds

全程面试辅导,保驾护航!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/661592.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Backend - Django CSRF 跨域请求伪造

目录 一、CSRF & XSS &#xff08;一&#xff09;CSRF 1. 含义 2. 攻击原理 &#xff08;1&#xff09;浏览器特点 &#xff08;2&#xff09;攻击方式 &#xff08;二&#xff09;XSS 1. 含义 2. 攻击原理 &#xff08;三&#xff09;二者区别 二、Django Ajax…

JavaScript基础(二)—— 运算符、表达式与语句(if、switch、循环)

学习目标&#xff1a; 掌握常见运算符&#xff0c;为程序“能思考”做准备 掌握分支语句&#xff0c;让程序具备判断能力 掌握循环语句&#xff0c;让程序具备重复执行能力 一、运算符 1. 赋值运算符 对变量进行赋值的运算符&#xff0c;能够使用赋值运算符简化代码。 …

推荐系统|概要03_AB测试

文章目录 A/B测试问题流量不够用解决方案——分层实验 Holdout 机制 A/B测试 其中小流量是指对部分的用户先尝试改进的算法模型&#xff0c;而非全部。若为全部&#xff0c;如果算法模型存在问题&#xff0c;可能会导致用户体验差&#xff0c;导致用户流失&#xff0c;而小流量…

Kubernetes实战(二十二)-Pod时区修改

一般国内引用的基础镜像时区都是 UTC 时区&#xff0c;在此基础上&#xff0c;如果去容器查看日志的话就会发现和本地时间对不上&#xff0c;会导致一些问题出现&#xff0c;比如输出的日志时间和当前不一致&#xff0c;所以一般都会把操作系统或容器里的时区替换为 Shanghai。…

深入探究iframe:网页嵌入的魔法盒子(下)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

DATAX改造支持geometry类型数据同步

数据库使用postgresql安装了postgis插件存储了geometry空间数据&#xff0c;想使用datax做数据同步&#xff0c;但datax本身不支持geometry类型数据&#xff0c;如何改造呢&#xff1f; 1.首先下载已改造支持geometry类型的datax引擎&#xff0c;下载地址 https://download.c…

Jmeter性能测试: Jmeter 5.6.3 分布式部署

目录 一、实验 1.环境 2.jmeter 配置 slave 代理压测机 3.jmeter配置master控制器压测机 4.启动slave从节点检查 5.启动master主节点检查 6.运行jmeter 7.观察jmeter-server主从节点变化 二、问题 1.jmeter 中间请求和响应乱码 一、实验 1.环境 &#xff08;1&#…

oracle数仓rac两个节点查询耗时不一致问题处理

问题描述 数据库节点1查询比节点2查询慢。现场操作应用发现发现同一sql语句在节点2上只要2分钟左右&#xff0c;在节点1&#xff0c;该条sql执行要超过30分钟。 处理过程 根据问题&#xff0c;初步判断是由于错误的执行计划&#xff0c;导致性能问题&#xff0c;但实际上对两…

编程流程图

对于复杂流程&#xff0c;我做开发之前一般会 先画一下流程图。特别是多个部门有交叉的情况下&#xff1a; processOn&#xff1a; 这个是我之前 一直的选择&#xff0c;他可以画上面的这些&#xff0c;流程图&#xff0c;网页操作&#xff0c;但是他不是免费的&#xff0c;查过…

MySQL常用命令集

1、数据库操作 1.1、显示数据库列表 show databases; 1.2、显示库中的数据表 use mysql; show tables; 1.3、显示数据表的结构 describe 表名; 1.4、建库 create database 库名; 1.5、建表 use 库名&#xff1b; create table 表名 (字段设定列表)&#xff1b; 1.…

leetcode LCP 24. 数字游戏【等价转换+对顶堆维护中位数】

原题链接&#xff1a;LCP 24. 数字游戏 题目描述&#xff1a; 小扣在秋日市集入口处发现了一个数字游戏。主办方共有 N 个计数器&#xff0c;计数器编号为 0 ~ N-1。每个计数器上分别显示了一个数字&#xff0c;小扣按计数器编号升序将所显示的数字记于数组 nums。每个计数器…

JavaScript事件冒泡和捕获

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ ​ ✨ 前言 事件传播是JavaScript中非常重要的一个概念,它描述了从嵌套元素到祖先…

【C++干货铺】哈希结构在C++中的应用

目录 unordered系列关联式容器 unordered_map unordered_map的接口说明 1.unordered_map的构造 2. unordered_map的容量 3. unordered_map的迭代器 4. unordered_map的元素访问 5. unordered_map的查询 6. unordered_map的修改操作 7. unordered_map的桶操作 底层结构 …

mysql+node.js+html+js完整扫雷项目

一.下载 可以直接下载绑定资源&#xff0c; 也可以访问&#xff1a;克隆仓库&#xff1a;mine_clearance: mysqlnode.jshtmljs完整扫雷项目 (gitee.com) 二.运行sql数据文件 将mysql数据文件导入到本地 先在本地localhost里创建数据库 mine_clearance&#xff0c; 然后如图&…

elementUI实现selecttree自定义下拉框树形组件支持多选和搜索

elementUI实现selecttree自定义下拉框树形组件支持多选和搜索 效果图定义子组件父组件应用 效果图 定义子组件 主要结合el-select和el-tree两个组件改造的。 <template><div class"selectTree"><el-select filterable :filter-method"filterMe…

微软给Windows 11增添了一个由AI支持的‘Voice Clarity’功能

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

linux搭建jupyter

查看虚拟环境 conda info --envs进入虚拟环境 conda activate my_env pip install jupyter pip install ipykernel1. jupyter notebook启动 1.1 创建临时jupyter notebook任务 jupyter notebook --ip0.0.0.0 --no-browser --allow-root --notebook-dir/home/xxx1.2 jupyter…

共用体与枚举法,链表的学习

结构体注意事项&#xff1a; 1.结构体类型可以定义在main函数里面&#xff0c;但是此时的作用域就被限定在该函数中 2.结构体的的的定义的形式&#xff1a;a.先定义类型&#xff0c;后定义变量-----struct stu s b.定义类型的同时&#xff0c;定义了变量&#xff1a;struct…

Notion 开源替代品:兼容 Miro 绘图 | 开源日报 No.162

toeverything/AFFiNE Stars: 25.6k License: NOASSERTION AFFiNE 是下一代知识库&#xff0c;将规划、排序和创建集于一身。它是一个注重隐私、开源、可定制且即插即用的替代方案&#xff0c;可以与 Notion 和 Miro 相媲美。主要功能和优势包括&#xff1a; 超融合&#xff1…

轻松使用python将PDF转换为图片(成功)

使用PyMuPDF&#xff08;fitz&#xff09;将PDF转换为图片 在处理PDF文件时&#xff0c;我们经常需要将PDF页面转换为图片格式&#xff0c;以便于在网页、文档或应用程序中显示。Python提供了多种方式来实现这一需求&#xff0c;本文将介绍如何使用PyMuPDF&#xff08;也称为f…