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

你好,我是田哥

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis常见数据类型[上]

目录 前言&#xff1a; 基本全局命令 KEYS EXISTS DEL EXPIRE TTL TYPE 数据结构和内部编码 内部编码&#xff1a; 单线程架构 引出单线程模型&#xff1a; 为什么单线程还这么快&#xff1f; String字符串 字符串数据类型&#xff1a; 常见命令&#xff1a; S…

第十四篇【传奇开心果系列】BeeWare的Toga开发移动应用示例:Toga实现页面切换

传奇开心果系列博文 系列博文目录BeeWare的Toga开发移动应用示例系列博文目录前言一、Toga页面跳转和切换方式方法介绍二、使用TabView来实现页面切换三、使用页面堆栈管理器(Page Stack Manager)来实现页面切换四、使用网格布局(Grid Layout)和可见性控制来实现页面之间的…

防御保护--NAT策略

目录 NAT策略 NAT类型 server-map表 P2P --- peer to peer 网络类型 ​编辑 目标NAT--服务器映射 双向NAT ​编辑 多出口NAT NAT策略 静态NAT --- 一对一 动态NAT --- 多对多 NAPT --- 一对多的NAPT --- easy ip --- 多对多NAPT 服务器映射 源NAT--基于源IP地址进行转…

算法:分界线

一、算法描述 电视剧《分界线》里面有一个片段&#xff0c;男主为了向警察透露案件细节&#xff0c;且不暴露自己&#xff0c;于是将报刊上的字 剪切下来&#xff0c;剪拼成匿名信。 现在有一名举报人&#xff0c;希望借鉴这种手段&#xff0c;使用英文报刊完成举报操作。 但为…

如何从视频中提取高清图片?可以这样截取

如何从视频中提取高清图片&#xff1f;从视频中提取高清图片可以方便我们制作各种用途所需的素材&#xff0c;如海报、社交媒体配图等。此外&#xff0c;高清图片的细节和色彩也更丰富&#xff0c;可以更好地满足我们的视觉需求。从视频中提取高清图片是一项需要技巧的任务&…

leetcode 27.移除元素(python版)

需求 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度…

代码随想录 Leetcode617.合并二叉树

题目&#xff1a; 代码(首刷看解析 2024年1月31日&#xff09;&#xff1a; class Solution { public:TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {if (!root1) return root2;if (!root2) return root1;root1->val root2->val;root1->left mergeTree…

计算机网络_1.2因特网概述

1.2因特网概述 一、网络、互联网与因特网的区别与联系1、网络2、互联网3、因特网4、 互联网与因特网辨析 二、因特网介绍1、因特网发展的三个阶段2、因特网简介&#xff08;1&#xff09;因特网服务提供者&#xff08;ISP&#xff09;&#xff08;2&#xff09;因特网已经发展成…

数字孪生智慧能源电力Web3D可视化云平台合集

前言 能源电力的经济发展是中国式现代化的强大动力&#xff0c;是经济社会发展的必要生产要素&#xff0c;电力成本变化直接关系到工业生产、交通运输、农业生产、居民生活等各个方面&#xff0c;合理、经济的能源成本能够促进社会用能服务水平提升、支撑区域产业发展&#xf…

监测Tomcat项目宕机重启脚本(Linux)

1.准备好写好的脚本 #!/bin/sh # 获取tomcat的PID TOMCAT_PID$(ps -ef | grep tomcat | grep -v tomcatMonitor |grep -v grep | awk {print $2}) # tomcat的启动文件位置 START_TOMCAT/mnt/tomcat/bin/startup.sh # 需要监测的一个GET请求地址 MONITOR_URLhttp://localhost:…

Spring Cloud中@RefreshScope实现动态刷新的原理

在现代微服务架构中&#xff0c;Spring Cloud已经成为了一种流行的选择&#xff0c;它提供了许多用于构建和部署微服务的工具和库。其中&#xff0c;动态刷新配置是Spring Cloud中一个非常有用的特性&#xff0c;它允许我们在不重启服务的情况下更新配置。这个特性是通过Refres…

Java入门高频考查基础知识8(腾讯18问1.5万字参考答案)

刷题专栏&#xff1a;http://t.csdnimg.cn/gvB6r Java 是一种广泛使用的面向对象编程语言&#xff0c;在软件开发领域有着重要的地位。Java 提供了丰富的库和强大的特性&#xff0c;适用于多种应用场景&#xff0c;包括企业应用、移动应用、嵌入式系统等。 以下是几个面试技巧&…

c#鼠标绘制

有用的没用的&#xff0c;用的上的用不上的&#xff0c;能写的不能写的&#xff0c;反正想起来就写了&#xff0c;比如这篇&#xff0c;好像一般也没什么用&#xff0c;emmm&#xff0c;或许&#xff0c;做录制软件的时候可以用一下。 顾名思义&#xff0c;本篇主要就是来实现将…

Linux上搭建mqtt开发环境及服务器部署(MosquittoEMQX)

&#x1f449;&#x1f449;&#x1f449;关于Mosquitto代码编写及EMQX的使用&#xff0c;由此入 一、安装编译Mosquitto 使用Mosquitto编写程序连接MQTT服务器&#xff0c;并收发数据1-安装所需依赖 用于在Linux系统上进行SSL/TLS加密通信的开发。它提供了一组用于加密和解密…

dvwa靶场xss储存型

xss储存型 xxs储存型lowmessage框插入恶意代码name栏插入恶意代码 medium绕过方法 high xxs储存型 攻击者事先将恶意代码上传或储存到漏洞服务器中&#xff0c;只要受害者浏览包含此恶意代码的页面就会执行恶意代码。产生层面:后端漏洞特征:持久性的、前端执行、储存在后端数据…

vue前端页面时间显示问题解决方法

解决方法&#xff0c; <template slot-scope"scope"><span>{{ parseTime(scope.row.boxClosingOnlineTime, {y}-{m}-{d} {h}:{i}:{s}) }}</span> </template> 刷新页面&#xff1a; 此外&#xff0c;使用JsonFormat(pattern "yyyy-M…

天气预警API:提升公共安全与紧急响应效率的关键技术

摘要 随着全球气候变化的加剧&#xff0c;极端天气事件的频发对公共安全构成了巨大挑战。为了有效应对这些挑战&#xff0c;天气预警API作为一种关键技术&#xff0c;正在逐渐成为提升公共安全与紧急响应效率的重要工具。本文将探讨天气预警API的工作原理、应用场景以及如何通…

全国生态服务功能区数据,shp格式,2008年,来源于国家生态环境部发布的《全国生态功能区》2008年版

数据名称: 全国生态服务功能区数据 数据格式: Shp 数据时间: 2008年 数据几何类型: 面 数据坐标系: WGS84 数据来源&#xff1a;国家生态环境部发布的《全国生态功能区》2008年版 数据字段&#xff1a; 序号字段名称字段说明1bh编号2mc名称3stgn_1生态功能一级区4s…

Oracle 锁的概念以及分类

1.什么是锁 数据库是一个庞大的多用户数据管理系统&#xff0c; 同一时刻可能有多个用户同时操作。事务的分离性要求当前事务不能影响其他的事务&#xff0c;所以多个会话操作同一个资源时&#xff0c;数据库会利用锁确保他们像队列一样一次执行。利用来锁消除多个用户操作同一…

删除有序数组中的重复项[简单]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给你一个非严格递增排列的数组nums&#xff0c;请你原地删除重复出现的元素&#xff0c;使每个元素只出现一次&#xff0c;返回删除后数组的新长度。元素的相对顺序应该保持一致。然后返回nums中唯一元素的个数。 考虑nums的唯一元素…