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

news2024/10/7 0:50:24

你好,我是田哥

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

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 = 123456

spring.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.coloradmin.cn/o/1423599.html

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

相关文章

实战教程:使用Spring Boot和Vue.js开发社区团购管理系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

【Docker】了解Docker Desktop桌面应用程序,TA是如何管理和运行Docker容器(1)

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Docker容器》序列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…

linux安装mongodb数据库启动报错? 都是冰红茶滴水儿

先展示报错信息 网上一大推说是关闭不正确导致的,然后给出的解决方法是 ./mongod -f mongodb.conf --repair吊用没有,还是报错: about to fork child process, waiting until server is ready for connections. forked process: 302226 ERROR: child process failed, exited…

资深Android逆袭、华为鸿蒙为安卓程序员开辟了一条新道路

本文章主要从以下5个方面来展开聊聊这个话题&#xff1a; 1.什么是鸿蒙 2.鸿蒙系统发展时间线 3.鸿蒙是套壳Android吗&#xff1f; 4.鸿蒙的生态&#xff08;用户以及开发者&#xff09; 5.一些建议 1月18日&#xff0c;在鸿蒙生态千帆启航仪式上&#xff0c;华为宣布了继鸿蒙4…

【原创】VMware创建子网,并使用软路由获得访问互联网的能力,并通过静态路由让上层网络访问位于虚拟机的子网

前言 一看标题就很离谱&#xff0c;确实内容也有点复杂&#xff0c;我的初衷是为后面搞软路由做准备&#xff0c;先通过VMware进行可行性验证&#xff0c;确定方案是否可行&#xff0c;再做下一步的计划。结论当然可以的&#xff0c;能通能访问&#xff0c;强的不行。 网络拓…

jdk17新特性—— 密封类(Sealed Classes)

目录 一、密封类(Sealed Classes)的概述1.1、概述1.2、特性1.3、注意事项 二、密封类(Sealed Classes)代码示例2.1、密封类(Sealed Classes)代码结构示例2.2、密封类(Sealed Classes)代码示例 三、密封类(Sealed Classes)接口代码示例3.1、密封类(Sealed Classes)接口代码结构示…

项目解决方案:4G/5G看交通数字化视频服务平台技术方案

目 录 1.总体描述 2.系统结构图 3.系统功能 3.1 信息交互 3.2 语音对讲 3.3 实时码流转换 3.4 流媒体集群和扩容 3.5 负载均衡 3.6 流媒体分发 3.7 流媒体点播 4.系统标准 4.1 流媒体传输 4.2 视频格式 4.3 质量标准 5.设备清单 1.总体描述 视频监控平…

LabVIEW潜油电泵数据采集系统

LabVIEW潜油电泵数据采集系统 介绍一个基于LabVIEW的潜油电泵数据采集系统。该系统目的是通过高效的数据采集和处理&#xff0c;提高潜油电泵的性能监控和故障诊断能力。 系统由硬件和软件两部分组成。硬件部分主要包括数据采集卡、传感器和电泵等&#xff0c;而软件部分则是…

STM32实时时钟(RTC)的配置和使用方法详解

实时时钟&#xff08;RTC&#xff09;是STM32系列微控制器上的一个重要模块&#xff0c;用于提供准确的时间和日期信息。在本文中&#xff0c;我们将详细介绍STM32实时时钟的配置和使用方法。 ✅作者简介&#xff1a;热爱科研的嵌入式开发者&#xff0c;修心和技术同步精进 ❤欢…

如何恢复已删除的照片?

在这篇综合文章中发现恢复丢失照片的有效且免费的方法。无论您使用的是智能手机、iPhone、Windows 计算机、Mac、SD 卡还是数码相机&#xff0c;我们都提供有关如何恢复已删除照片的分步说明。此外&#xff0c;学习一些有价值的技巧&#xff0c;以防止将来意外删除照片。 意外…

scienceplots绘图浅尝

前言 科研写作中&#xff0c;黑压压的文字里面如果能有一些优美的图片无疑会给论文增色不少&#xff0c;绘图的工具有很多&#xff0c;常用的有Excel、Python、Matlab等&#xff0c;Matlab在绘图方面相较于Python有一种更加原生的科研风&#xff0c;而且可视化编辑图例、坐标轴…

【数据结构与算法】之哈希表系列-20240130

这里写目录标题 一、383. 赎金信二、387. 字符串中的第一个唯一字符三、389. 找不同四、409. 最长回文串五、448. 找到所有数组中消失的数字六、594. 最长和谐子序列 一、383. 赎金信 简单 给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不…

三分钟教你入门规则引擎Drools

Drools是一款基于Java语言的开源的规则引擎&#xff0c;可以将复杂且多变的规则从硬编码中解放出来&#xff0c;以规则脚本的形式存放在文件或者特定的存储介质中(eg:数据库表)&#xff0c;使得业务规则的变更不需要修正项目代码&#xff0c;重启服务器就可以在线上环境立即生效…

正则表达式 与文本三剑客(sed grep awk)

一&#xff0c;正则表达式 &#xff08;一&#xff09;正则表达式相关定义 1&#xff0c;正则表达式含义 REGEXP&#xff1a; Regular Expressions&#xff0c;由一类特殊字符及文本字符所编写的模式&#xff0c;其中有些字符&#xff08;元字符&#xff09;不表示字符字面意…

【学网攻】 第(17)节 -- 命名ACL访问控制列表

系列文章目录 目录 前言 一、ACL(访问控制列表)是什么&#xff1f; 二、实验 1.引入 总结 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交换机配置聚合端口【学网攻】 第(4)节 -- 交换机划分Vlan【学网攻】 第…

Packet tracer-实现VLAN内部通信

案例一&#xff1a; 要求PC1和PC2&#xff0c;PC3和PC4之间能够实现互访 两个VLAN&#xff0c;一个VLAN对应一个子网 以S2为例&#xff1a; 步骤 1&#xff1a;在 S2 上创建并命令 VLAN&#xff0c;把VLAN划分给活动的端口。 步骤 2&#xff1a;在 S3 上创建并命令 VLAN&…

LeetCode Hot100 回顾(二)

子串 560.和为K的子数组 使用前缀和预处理一下题目给的数组, 然后用二重循环遍历一遍就可以了。 239.滑动窗口最大值 看题面比较容易想到的是用优先级队列来解决, 但是STL中的priority_queue不支持随机删除, 如果要用优先级队列来解决这道题的话比较复杂。这道题的一种正确…

QT + opengl 环境搭建(glfw, glad),创建一个简单窗口

一.下载glfw&#xff0c;glad并编译 1.glfw个人理解就是对底层opengl的一些基本接口的封装&#xff0c;提供了一些渲染物体所需的最低限度的接口。它允许用户创建OpenGL上下文、定义窗口参数以及处理用户输入。glfw的下载地址&#xff1a;Download | GLFW&#xff0c;下载完成后…

SpringBoot 结合 liteflow 规则引擎使用

1、前言 在日常的开发过程中&#xff0c;经常会遇到一些串行或者并行的业务流程问题&#xff0c;而业务之间不必存在相关性。 在这样的场景下&#xff0c;使用策略和模板模式的结合可以很好的解决这个问题&#xff0c;但是使用编码的方式会使得文件太多,在业务的部分环节可以…

15EG使用vivado2023.1建立hello world工程

1:打开软件建立工程 2:使用vivado创建设计模块并生成bit文件 3:导出硬件平台&#xff0c;使用vitis建立工程 4:使用vitis创建应用程序项目 5:硬件设置与调试 1:打开软件建立工程 打开VIVADO2023.1 创建一个新的工程 输入项目名称和地址&#xff0c;下面那个选项为是否…