使用Druid完成SpringBoot集成MySql、DM(达梦)数据库数据源操作

业务背景

一个方法里,对A数据源需要进行查询,B数据源进行插入(切面插入访问数据,日志)。

详细业务是查询业务数据,同时主数据库记录访问日志。

第一步依赖先行

<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency><dependency><groupId>com.dameng</groupId><artifactId>Dm8JdbcDriver18</artifactId><version>8.1.1.49</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.16</version></dependency>

配置类

package com.zhuao.config;import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.google.common.collect.Maps;
import com.zhuao.common.DynamicDataSource;
import com.zhuao.constant.DataSourceTypeConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
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 javax.sql.DataSource;
import java.util.Map;/*** @Description: 数据源配置* @author: Be.insighted* @create: 2024/7/15 11:35* @since 1.0.0*/
@Slf4j
@Configuration
public class DataSourceConfig {/*** 主数据源* @return*/@Bean(initMethod = "init", destroyMethod = "close")@ConfigurationProperties("dm.datasource")public DruidDataSource masterDataSource() {log.info("masterDataSource druid data-source init...");return DruidDataSourceBuilder.create().build();}/*** 从数据源* @return*/@Bean(initMethod = "init", destroyMethod = "close")@ConfigurationProperties("mysql.datasource")public DruidDataSource slaveDataSource() {log.info("slaveDataSource druid data-source init...");return DruidDataSourceBuilder.create().build();}/*** 动态数据源* @param masterDataSource masterDataSource* @param slaveDataSource  slaveDataSource* @return {@link DynamicDataSource}*/@Bean@Primarypublic DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("slaveDataSource") DataSource slaveDataSource) {Map<String, DataSource> pool = Maps.newHashMapWithExpectedSize(16);pool.put(DataSourceTypeConstant.MASTER, masterDataSource);pool.put(DataSourceTypeConstant.FIRST_FOLLOWER, slaveDataSource);return new DynamicDataSource(pool, masterDataSource);}
}

枚举数据库类型

public interface DataSourceTypeConstant {/*** 主数据源*/String MASTER = "MASTER";/*** 第1从数据源*/String FIRST_FOLLOWER = "FIRST_FOLLOWER";/*** 第2从数据源*/String SECOND_FOLLOWER = "SECOND_FOLLOWER";
}

切换数据源

package com.zhuao.common;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;import javax.sql.DataSource;
import java.util.Map;
import java.util.Stack;/*** @Description:* @author: lBe.insighted* @create: 2024/7/15 15:41* @since 1.0.0*/public class DynamicDataSource  extends AbstractRoutingDataSource {private static final ThreadLocal<Stack<String>> DATA_SOURCE_KEY = new InheritableThreadLocal<>();public static void setDataSourceKey(String dataSource) {Stack<String> stack = DATA_SOURCE_KEY.get();if (stack == null) {stack = new Stack<>();DATA_SOURCE_KEY.set(stack);}stack.push(dataSource);}public static void cleanDataSourceKey() {Stack<String> stack = DATA_SOURCE_KEY.get();if (stack != null) {stack.pop();if (stack.isEmpty()) {DATA_SOURCE_KEY.remove();}}}/*** 构造** @param targetDataSources*/@SuppressWarnings({"rawtypes", "unchecked"})public DynamicDataSource(Map<String, DataSource> targetDataSources, DataSource defaultDataSource) {super.setTargetDataSources((Map) targetDataSources);super.setDefaultTargetDataSource(defaultDataSource);}/*** determineCurrentLookupKey** @return* @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey()*/@Overrideprotected Object determineCurrentLookupKey() {Stack<String> stack = DATA_SOURCE_KEY.get();if (stack != null) {return stack.peek();}return null;}
}

切面处理

注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface DynamicDatasourceAnno {String value();
}

切面逻辑

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.zhuao.annotation.DynamicDatasourceAnno;
import com.zhuao.common.DynamicDataSource;
import com.zhuao.constant.DataSourceTypeConstant;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;/*** @Description:* @author: be.insighted* @create: 2024/7/15 15:42* @since 1.0.0*/@Component
@Aspect
@Slf4j
public class TypeSwitchDatasourceAspectJ {@Pointcut("@annotation(com.zhuao.annotation.DynamicDatasourceAnno)")public void pointcut() {}@Before(value="pointcut() && @annotation(dynamicDatasourceAnno)", argNames="dynamicDatasourceAnno")public void before(DynamicDatasourceAnno dynamicDatasourceAnno) {String dataSource = dynamicDatasourceAnno.value();if (StringUtils.isNotBlank(dataSource)) {log.info("从主数据源->切换到->从数据源({})", dataSource);DynamicDataSource.setDataSourceKey(dataSource);}}@After("pointcut()")public void after() {DynamicDataSource.cleanDataSourceKey();log.info("恢复主数据源");DynamicDataSource.setDataSourceKey(DataSourceTypeConstant.MASTER);}}

使用

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zhuao.annotation.DynamicDatasourceAnno;
import com.zhuao.constant.DataSourceTypeConstant;
import com.zhuao.entity.CtiTSheetRecord;
import com.zhuao.req.CtiTeleRecordReq;/*** @Description: 通话记录* @author: Be.insighted* @create: 2024/7/9 10:50* @since 1.0.0*/public interface CtiTSheetRecordService extends IService<CtiTSheetRecord> {@DynamicDatasourceAnno(DataSourceTypeConstant.FIRST_FOLLOWER)IPage<CtiTSheetRecord> query(Page<?> page, CtiTeleRecordReq req);
}

这样还不能完全实现数据源切换,服务无法启动

accountServiceImpl (field private com.******** ***Mapper)↓accountDao↓(inner bean)#12942633↓org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration
┌─────┐
|  dataSource defined in class path resource [com/******************/DataSourcesConfig.class]
↑     ↓
|  databusinessDataSource defined in class path resource [com/*********/DataSourcesConfig.class]
↑     ↓
|  org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker
└─────┘

druid循环依赖

/*** Specify the map of target DataSources, with the lookup key as key.* The mapped value can either be a corresponding {@link javax.sql.DataSource}* instance or a data source name String (to be resolved via a* {@link #setDataSourceLookup DataSourceLookup}).* <p>The key can be of arbitrary type; this class implements the* generic lookup process only. The concrete key representation will* be handled by {@link #resolveSpecifiedLookupKey(Object)} and* {@link #determineCurrentLookupKey()}.*/public void setTargetDataSources(Map<Object, Object> targetDataSources) {this.targetDataSources = targetDataSources;}/*** Specify the default target DataSource, if any.* <p>The mapped value can either be a corresponding {@link javax.sql.DataSource}* instance or a data source name String (to be resolved via a* {@link #setDataSourceLookup DataSourceLookup}).* <p>This DataSource will be used as target if none of the keyed* {@link #setTargetDataSources targetDataSources} match the* {@link #determineCurrentLookupKey()} current lookup key.*/public void setDefaultTargetDataSource(Object defaultTargetDataSource) {this.defaultTargetDataSource = defaultTargetDataSource;}

解决druid循环依赖问题


1.启动时排除DataSourceAutoConfiguration

 2.用import以全路径的形式注入bean

/*** *  解决druid循环依赖问题*  1.启动时排除DataSourceAutoConfiguration*  2.用import以全路径的形式注入bean* */
@EnableAspectJAutoProxy
@Import(DataSourcesConfig.class)
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class BusinessApplication {public static void main(String[] args) {SpringApplication.run(BusinessApplication.class, args);}}

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

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

相关文章

正确选择指挥中心操作台厂家的因素

在当今数字化和信息化快速发展的时代&#xff0c;指挥中心操作台在各类机构和企业的运营中发挥着至关重要的作用。然而&#xff0c;选择一个合适的指挥中心操作台厂家并非易事。以下是一些选择指挥中心操作台厂家的考虑因素。 一、产品质量与工艺 要考察厂家的产品质量和工艺水…

C语言中的指针:掌握内存的钥匙

C语言中的指针&#xff1a;掌握内存的钥匙 引言 C语言是一种结构化编程语言&#xff0c;它提供了对硬件底层的直接访问&#xff0c;其中最强大的特性之一就是指针。指针允许程序员直接操作内存地址&#xff0c;这对于理解程序的内部工作原理以及优化代码性能至关重要。本文将深…

解决宝塔Spring Boot项目获取不到环境变量的问题

问题描述 在使用宝塔面板管理Spring Boot项目时&#xff0c;可能会遇到代码无法获取 /etc/profile 文件中设置的Linux环境变量的问题。虽然在SSH终端中可以正常获取&#xff0c;但在通过宝塔面板启动的Spring Boot项目中&#xff0c;环境变量却无法被读取。 解决方案&#xf…

量化交易研究报告#13

核心公式 通过对 HS300 相对强弱指标值变化规律的梳理&#xff0c;我们制定如下的交易法则&#xff1a; &#xff08;1&#xff09;计算指标的 20 日均值变化&#xff0c;以及 20 日标准差&#xff1b; &#xff08;2&#xff09;20日均值1倍标准差作为上阈值&#xff0c;20…

【Chapter 3: Creating Minimal API Applications】

Chapter 1: Foundations of Framework Learning and Practical Strategies Chapter 2: An Introduction to ASP.NET Core in Layman‘s Terms Chapter 3: Creating Minimal API Applications 1. Overview of Minimal APIs In the vast landscape of ASP.NET Core, “Minima…

Mysql表的三范式、事务和查询

数据表的三范式 在制定数据表,需要遵循的制表规范:第一范式(1NF),第二范式(2NF),第三范式(3NF) 第一范式 属性不可分割,每一个属性(每一个单元格)都是不可再分的原子,也就是说数据表中的每一个字段必须是单独一列的,不能出现还可以再拆分的情况,也可以说成是…

数电基础 - 半导体存储

目录 一. 简介 一. 只读存储器 二. 可编程只读存储器 三. 可擦除的可编程只读存储器 四. 随机存储器 五. 存储器容量的扩展 六. 总结 一. 简介 半导体存储是数字电路中用于存储数据的重要组成部分。 半导体存储器主要分为两大类&#xff1a;随机存取存储器&#xff0…

【人工智能】Transformers之Pipeline(二):自动语音识别(automatic-speech-recognition)

​​​​​​​ 目录 一、引言 二、自动语音识别&#xff08;automatic-speech-recognition&#xff09; 2.1 概述 2.2 技术原理 2.2.1 whisper模型 2.2.2 Wav2vec 2.0模型 2.3 pipeline参数 2.3.1 pipeline对象实例化参数​​​​​​​ 2.3.2 pipeline对象使用参数…

16001.WSL2 ubuntu20.04 编译安装 vsomeip

文章目录 1 vsomeip 编译安装1.1 vsomeip的安装1.2 编译提示错误1.3 编译hello_world示例1.4 运行服务器端 1 vsomeip 编译安装 1.1 vsomeip的安装 参考博文 https://blog.csdn.net/peterwanye/article/details/128386539 1.2 编译提示错误 ubuntu1-BJ-EE1000042:~/opt/vso…

Flask启动5000端口后关不掉了?

事情是这样的&#xff1a; 使用python app.py启动flask应用后&#xff0c;又启动了另一个flask测试应用&#xff0c;也能启动成功&#xff0c;也没有报设么端口冲突&#xff0c;关闭黑窗口后&#xff0c;访问还是有守护进程在运行&#xff0c; 为什么我知道5000还在运行&#…

深入理解缓冲区:提升程序性能的关键

深入理解缓冲区&#xff1a;提升程序性能的关键 1、什么是缓冲区&#xff1f;2、缓冲区的作用3、缓冲区在Java中的应用4、如何操作缓冲区5、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 缓冲区&#xff08;Buffer&#xff09;是一种…

2024Datawhale AI夏令营---基于术语词典干预的机器翻译挑战赛--学习笔记

#Datawhale #NLP 1.背景介绍&#xff1a; 机器翻译&#xff08;Machine Translation&#xff0c;简称MT&#xff09;是自然语言处理领域的一个重要分支&#xff0c;其目标是将一种语言的文本自动转换为另一种语言的文本。机器翻译的发展可以追溯到20世纪50年代&#xff0c;经历…

07:串口通信二

串口编程 1、与波特率之相关的寄存器2、PCON寄存器3、SCON寄存器4、配置的代码分析5、向PC发送一段字符串6、PC机向单片机发送字符控制LED1灯的亮灭 1、与波特率之相关的寄存器 如图&#xff0c;与串口通信相关的寄存器主要是SCON和PCON寄存器。 2、PCON寄存器 SMOD&#xff1…

信息素养大赛-2024-算法创意实践挑战复赛-小学组

文章目录 一、前言二、问题问题&#xff1a;玫瑰花地的面积问题&#xff1a;判断三角形问题&#xff1a;汤姆的日记问题&#xff1a;正方形的数量问题&#xff1a;字符操作问题&#xff1a;猴子摘桃 三、感谢 一、前言 本章节主要对2024年信息素养大赛算法创意实践挑战复赛小学…

通用图形处理器设计GPGPU基础与架构(三)

一、前言 前两篇已经介绍了 GPGPU 的背景 和 GPGPU 的编程模型相关的内容&#xff0c;本文将在 SIMT 计算模型的基础上&#xff0c;介绍 GPGPU 控制核心架构和微体系结构的设计。 二、CPU-GPGPU 异构计算系统 一个由 CPU 和 GPGPU 构成的异构计算平台如下图所示&#xff0c;GP…

开源AI智能名片S2B2C商城小程序:重塑营销一体化新生态,引领未来商业潮流!

在互联网时代&#xff0c;尤其是移动互联网的迅猛发展下&#xff0c;顾客的认知与购买行为发生了翻天覆地的变化。曾经&#xff0c;顾客的认知和购买是两个相对独立的过程&#xff0c;不仅时间不同步&#xff0c;空间上也存在明显的分离。但如今&#xff0c;微信、App、电子商务…

MATLAB中Simulink.SimulationData.Dataset用法

目录 语法 说明 示例 访问使用Dataset格式记录的数据 打开模型vdp 使用 Dataset 对象来组合模拟输入信号 Simulink.SimulationData.Dataset的功能是访问已记录的模拟数据或组合模拟输入数据。 语法 ds Simulink.SimulationData.Dataset ds Simulink.SimulationData.Da…

如何在gitee上创建远程仓库?

登录gitee网站后 填写自己的仓库信息后点击创建 然后来到一个新的界面可以看到自己的仓库地址 这样一个空白的仓库就建立好了 也可以按需选择初始化仓库

jmeter-beanshell学习10-字符串补齐位数

每天都遇到新问题&#xff0c;今天又一个场景&#xff0c;一个字符串&#xff0c;如果不足11位&#xff0c;则左边补0&#xff0c;补够11位。 先要获取字符串长度&#xff0c;然后计算差多少位&#xff0c;补齐。今天又发现一个Object类型&#xff0c;这个类型有点厉害&#x…

ARM 虚拟机FVP环境搭建

ARM Fixed Virtual Platforms (FVPs) 是由 ARM 提供的一系列虚拟化硬件模拟器&#xff0c;用于在物理硬件可用之前开发和测试软件。FVP 模型非常适用于软件开发、验证和性能分析&#xff0c;涵盖了从裸机到操作系统和复杂 SoC 系统的各种应用。 这里以Cortex-M55为例&#xff0…