当前位置: 首页 > news >正文

基于SpringBoot+Druid实现多数据源:原生注解式

前言

本博客姊妹篇

  • 基于SpringBoot+Druid实现多数据源:原生注解式
  • 基于SpringBoot+Druid实现多数据源:注解+编程式
  • 基于SpringBoot+Druid实现多数据源:baomidou多数据源

一、功能描述

  • 配置方式:配置文件中实现多数据源,非动态
  • 使用方式:使用注解切换数据源

二、代码实现

2.1 配置

# spring配置
spring:# 数据源配置datasource:type: com.alibaba.druid.pool.DruidDataSourcedruid:web-stat-filter:enabled: trueurl-pattern: /*exclusions: '*.js,*.css,*.gif,*.png,*.jpg,*.ico,/druid/*'stat-view-servlet:enabled: trueurl-pattern: /druid/*login-username: adminlogin-password: 123456filter:stat:enabled: truelog-slow-sql: trueslow-sql-millis: 1000merge-sql: truewall:enabled: trueconfig:multi-statement-allow: truemaster:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/boot_business?useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8&useSSL=falseusername: rootpassword: rootinitial-size: 10min-idle: 10max-active: 100max-wait: 60000time-between-eviction-runs-millis: 60000min-evictable-idle-time-millis: 300000validation-query: select 1test-while-idle: truetest-on-borrow: falsetest-on-return: falsepool-prepared-statements: truemax-pool-prepared-statement-per-connection-size: 20slave:enabled: truedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/boot_codegen?useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8&useSSL=falseusername: rootpassword: rootinitial-size: 10min-idle: 10max-active: 100max-wait: 60000time-between-eviction-runs-millis: 60000min-evictable-idle-time-millis: 300000validation-query: select 1test-while-idle: truetest-on-borrow: falsetest-on-return: falsepool-prepared-statements: truemax-pool-prepared-statement-per-connection-size: 20

2.2 配置类

package com.qiangesoft.datasource.core;import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;import java.util.HashMap;
import java.util.Map;/*** 多数据源配置** @author qiangesoft* @date 2024-03-14*/
@Slf4j
@Configuration
public class DataSourceConfiguration {@Bean@ConfigurationProperties("spring.datasource.druid.master")public DruidDataSource masterDataSource() {DruidDataSource masterDataSource = DruidDataSourceBuilder.create().build();masterDataSource.setName(DataSourceType.MASTER.getType());return masterDataSource;}@Bean@ConfigurationProperties("spring.datasource.druid.slave")@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")public DruidDataSource slaveDataSource() {DruidDataSource slaveDataSource = DruidDataSourceBuilder.create().build();slaveDataSource.setName(DataSourceType.SLAVE.getType());return slaveDataSource;}@Bean@Primarypublic DynamicDataSource dynamicDataSource(DruidDataSource masterDataSource, DruidDataSource slaveDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(masterDataSource.getName(), masterDataSource);targetDataSources.put(slaveDataSource.getName(), slaveDataSource);return new DynamicDataSource(masterDataSource, targetDataSources);}
}

2.3 多数据源扩展实现

package com.qiangesoft.datasource.core;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;import javax.sql.DataSource;
import java.util.Map;/*** 动态数据源** @author qiangesoft* @date 2024-03-14*/
public class DynamicDataSource extends AbstractRoutingDataSource {public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {super.setDefaultTargetDataSource(defaultTargetDataSource);super.setTargetDataSources(targetDataSources);super.afterPropertiesSet();}@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContext.getDataSource();}
}

2.4 切面

package com.qiangesoft.datasource.core;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import java.util.Objects;/*** 多数据源处理** @author qiangesoft* @date 2024-03-14*/
@Slf4j
@Order(1)
@Aspect
@Component
public class DataSourceAspect {/*** 切点*/@Pointcut("@annotation(com.qiangesoft.datasource.core.DataSource)")public void pointCut() {}/*** 通知** @param joinPoint* @return* @throws Throwable*/@Around("pointCut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {DataSource dataSource = this.getDataSource(joinPoint);if (dataSource == null) {DataSourceContext.setDataSource(DataSourceType.MASTER);} else {DataSourceContext.setDataSource(dataSource.value());}try {return joinPoint.proceed();} finally {DataSourceContext.removeDataSource();}}/*** 获取数据源** @param joinPoint* @return*/public DataSource getDataSource(ProceedingJoinPoint joinPoint) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();// 方法上查找注解DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);if (Objects.nonNull(dataSource)) {return dataSource;}// 类上查找注解return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);}
}

2.5 线程本地变量

package com.qiangesoft.datasource.core;/*** 数据源上下文** @author qiangesoft* @date 2024-03-14*/
public class DataSourceContext {/*** 线程本地变量:数据源*/private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();/*** 设置数据源的变量*/public static void setDataSource(DataSourceType dataSourceType) {CONTEXT_HOLDER.set(dataSourceType.getType());}/*** 获得数据源的变量*/public static String getDataSource() {return CONTEXT_HOLDER.get();}/*** 清空数据源变量*/public static void removeDataSource() {CONTEXT_HOLDER.remove();}
}

2.6 使用

package com.qiangesoft.datasource.controller;import com.qiangesoft.datasource.core.DataSource;
import com.qiangesoft.datasource.core.DataSourceType;
import com.qiangesoft.datasource.entity.SysUser;
import com.qiangesoft.datasource.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** <p>* 用户信息 前端控制器* </p>** @author qiangesoft* @since 2024-03-14*/
@RestController
@RequestMapping("/sys/user")
public class SysUserController {@Autowiredprivate ISysUserService sysUserService;@DataSource(DataSourceType.MASTER)@GetMapping("/master")public List<SysUser> listMaster() {return sysUserService.list();}@DataSource(DataSourceType.SLAVE)@GetMapping("/slave")public List<SysUser> listSlave() {return sysUserService.list();}}

相关文章:

基于SpringBoot+Druid实现多数据源:原生注解式

前言 本博客姊妹篇 基于SpringBootDruid实现多数据源&#xff1a;原生注解式基于SpringBootDruid实现多数据源&#xff1a;注解编程式基于SpringBootDruid实现多数据源&#xff1a;baomidou多数据源 一、功能描述 配置方式&#xff1a;配置文件中实现多数据源&#xff0c;非…...

AJAX 03 XMLHttpRequest、Promise、封装简易版 axios

AJAX 学习 AJAX 3 原理01 XMLHttpRequest① XHR 定义② XHR & axios 关系③ 使用 XHR④ XHR查询参数案例&#xff1a;地区查询&#xff08;URLSearchParams&#xff09;⑤ XHR数据提交 POST 02 PromisePromise 使用Promise - 三种状态案例&#xff1a;使用Promise XHR 获取…...

如何将办公资料文件生成二维码?扫码可看详情

日常办公的时候&#xff0c;经常会需要应用二维码来向同事或者客户发送和展示一些资料。比如包含企业介绍和产品介绍的资料、一些操作流程的资料、产品展示宣传视频、活动安排详情、比赛流程、会议资料… 这些都能通过一个文件二维码来展示。 文件二维码支持将PDF文件生成二维…...

【Streamlit学习笔记】实现包含多个sheet的excel文件下载

1、什么是Streamlit Streamlit是一个免费的开源框架&#xff0c;用于快速构建和共享漂亮的机器学习和数据科学Web应用程序&#xff0c;官网链接 Streamlit Streamlit API链接 API reference 实际项目中遇到的问题&#xff1a;包含多个sheet的excel文件下载&#xff0c;下面将给…...

[Redis]——主从同步原理(全量同步、增量同步)

目录 Redis集群&#xff1a; 主从同步原理&#xff1a; replid和offset: 全量同步和增量同步&#xff1a; repl_baklog文件&#xff1a; 主从集群的优化&#xff1a; Redis集群&#xff1a; 部署多台Redis我们称之为Redis集群&#xff0c;他有一个主节点(负责写操作)&…...

Buildroot 之二 详解构建架构、流程、external tree、示例

构建系统 Buildroot 中的构建系统使用的是从 Linux Kernel(4.17-rc2) 中移植的 Kconfig(配置) + Makefile & Kbuild(编译)这套构建系统,移植后的源码位于 support/kconfig/ 目录下。Buildroot 本身是一个构建系统,与直接编译源码不同,因此,它对这套系统进行了比较…...

牛客小白月赛61-C-小喵觅食

很经典的bfs,就是从猫咪和MM的坐标开始bfs搜索 不过这题有些小细节需要注意 1.认真审题,注意,猫一旦闻到小鱼干的味道,开始动,此时MM就不动了,一开始没仔细审题,很不好的习惯 2.注意移动的条件,vis,不是墙,距离是MM的移动距离范围内 3.这个猫咪的r2是闻味道的r2,不是移动距…...

200 名专家编写报告:AI 发展可能对人类构成「灭绝级威胁」

3 月 14 日消息&#xff0c;美国国务院委托编写了一份新报告&#xff0c;警告 AI 正呈指数级发展&#xff0c;可能会对人类构成「灭绝级威胁」。 这份报告全称为《提高先进人工智能安全保障的行动计划》&#xff0c;要求美国政府必须迅速、果断地采取行动&#xff0c;以避免 A…...

学习Android的第二十九天

目录 Android Service 与 Activity 通讯 范例 Android Service Alarm 定时广播 Alarm Alarm 使用流程 范例 Android IBinder Binder 为什么是 Binder ? Android Service 与 Activity 通讯 Activity 与 Service 通信的媒介就是 Service 中的 onBind() 方法&#xff0…...

SpringMVC重点记录

目录 1.学习重点2.回顾MVC3.回顾servlet4.初始SpringMVC4.1.为什么要学SpringMVC?4.2.SpringMVC的中重点DispatcherServlet4.3.SpringMVC项目的搭建4.4.MVC框架要做哪些事情?4.5.可能会遇到的问题 5.SpringMVC的执行原理6.使用注解开发SpringMVC7.Controller控制总结8.RestF…...

一条 SQL 更新语句如何执行的

Server 层 存储引擎层 总流程 查询语句 连接器 查询缓存 分析器 优化器 执行器 更新语句 redo log&#xff08;节省的是随机写磁盘的 IO 消耗&#xff08;转成顺序写&#x…...

Github上哪些好用的安全工具1

专注于web漏洞挖掘、内网渗透、免杀和代码审计&#xff0c;感谢各位师傅的关注&#xff01;网安之路漫长&#xff0c;与君共勉&#xff01; URLFinder 一款快速提取网页信息的工具。该项目可以快速爬取网页上的 URL 地址、JS 文件里的 API 接口等信息&#xff0c;支持批量抓取…...

手写Mybatis自动填充插件

目录 一、Mybatis插件简介&#x1f959;二、工程创建及前期准备工作&#x1f96b;实现代码配置文件 三、插件核心代码实现&#x1f357;四、测试&#x1f953; 一、Mybatis插件简介&#x1f959; Mybatis插件运行原理及自定义插件_简述mybatis的插件运行原理,以及如何编写一个…...

upload文件上传漏洞复现

什么是文件上传漏洞&#xff1a; 文件上传漏洞是指由于程序员在对用户文件上传部分的控制不足或者处理缺陷&#xff0c;而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。这里上传的文件可以是木马&#xff0c;病毒&#xff0c;恶意脚本或者WebShell等。“…...

Docker 安装部署 SqlServer 数据库

Docker 安装部署 SqlServer 数据库 背景&#xff1a; ​ 最近在开发数据中台数据集成模块&#xff0c;需要对接大量的数据做测试&#xff0c; 由于SqlServer 下载安装会耗费大量时间&#xff0c;所以采用 Docker 安装 Sqlserver 的方式部署数据库。 1、拉去 sqlserver 镜像 …...

cmath 中cos sin等常用函数的坑(弧度角度换算)

cmath中三角函数的输入是弧度,不是角度.忘了这件事,找bug找了好久! 弧度是旧称弪。在数学和物理中&#xff0c;弧度是角的度量单位。它是由国际单位制导出的单位&#xff0c;单位缩写是rad。弧度是指在一个圆中&#xff0c;弧长和半径之比&#xff0c;即|弧度|弧长半径。 角度…...

深度解析HTTP反向代理-okey proxy

反向代理這個概念可能並不常見&#xff0c;但其實它對於提升網路安全和訪問速度方面發揮著很大作用。 HTTP反向代理&#xff08;HTTP Reverse Proxy&#xff09;是一種特殊的代理伺服器&#xff0c;首先它能夠接收互聯網上的連接請求&#xff0c;然後將這些請求轉發給內部網路…...

SwinIR训练报错解决

swinir训练报错解决 记录swinir图像超分重建算法复现过程中的报错信息,并提供相应的解决方案 报错信息 UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at C:\actions-runner\_work\pyto…...

C++类和对象一

#include <iostream> using namespace std;//设计一个学生类 class CStudent {public: //公有成员void InputData(){cout << "请输入学号";cin >> sno;cout << "请输入姓名";cin >> sname;cout << "请输入分…...

Linux之线程互斥

目录 一、问题引入 二、线程互斥 1、相关概念 2、加锁保护 1、静态分配 2、动态分配 3、锁的原理 4、死锁 三、可重入与线程安全 1、概念 2、常见的线程不安全的情况 3、常见的线程安全的情况 4、常见不可重入的情况 5、常见可重入的情况 6、可重入与线程安全联系…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...