Springboot+druid+多数据源

背景:早期项目是springboot2.x + druid 的单数据源工程,其中使用了dblink的方式进行跨数据库访问。现在客户的机房搬迁,记账的下游数据库说是搬到不同区域,dblink的方式需要长期占用资源,需要修改成直连方式。

按照AI的指引采用:

 1.在Spring Boot中配置两个不同的Oracle数据源,你需要在配置类中分别定义两个数据源,并使用AbstractRoutingDataSource来路由到不同的数据源。以下是一个配置类的示例,展示了如何设置两个不同的Oracle数据源,并在应用中使用它们。1. 添加依赖确保pom.xml或build.gradle中包含Oracle JDBC驱动依赖。

Maven:

<dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>版本</version>
</dependency>

Gradle:

implementation 'com.oracle.database.jdbc:ojdbc8:版本'

2. 配置置文件在application.yml或application.properties中配置两个数据源的详细信息:

yaml:

spring:
  datasource:
    primary:
      driver-class-name: oracle.jdbc.driver.OracleDriver
      url: jdbc:oracle:thin:@localhost:1521/orclpdb1
      username: system
      password: manager
      platform: oracle
    secondary:
      driver-class-name: oracle.jdbc.driver.OracleDriver
      url: jdbc:oracle:thin:@localhost:15222/orclpdb2
      username: scott
      password: tiger
      platform: oracle

3. 配置置类创建配置类来定义和配置两个数据源,并设置路由逻辑:

@Configuration
public class OracleDataSourceConfig {

    @Primary
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource(DataSourceProperties properties) {
        return buildDataSource(properties, "primary");
    }

    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource(DataSourceProperties properties) {
        return buildDataSource(properties, "secondary");
    }

    private DataSource buildDataSource(DataSourceProperties properties, String dataSourceName) {
        HikariDataSource ds = properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
        ds.setPoolName(dataSourceName + "DataSource");
        return ds;
    }

    @Bean
    public AbstractRoutingDataSource dataSource(@Qualifier("primaryDataSource") DataSource primary, @Qualifier("secondaryDataSource") secondary) {
        AbstractRoutingDataSource router = new AbstractRoutingDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("primary", primary);
        targetDataSources.put("secondary", secondary);
        router.setTargetDataSources(targetDataSources);
        return router;
    }
}

4. 使用数据源在Service或Repository中,你可以通过@Qualifier指定数据源名称来使用特定的数据源:

@Service
public class UserService {

    private final UserRepository userRepository;

    @Autowired
    public UserService(@Qualifier("primaryDataSource") UserRepository userRepository) this.userRepository = userRepository;

    // your business code here
}

对于动态路由到不同的数据源,你可以使用AbstractRoutingDataSource的机制,通过某种方式动态设置dataSourceLookupKey来决定使用哪个数据源。动态切换数据源示例你可以定义一个简单的策略来决定使用哪个数据源,比如基于用户ID的奇偶数或某些业务逻辑:

public class DynamicDataSourceKeyResolver implements DataSourceLookup {

    @Override
    public DataSource determineCurrentLookupKey(Method method, Object[] args) {
        // 假设定一个逻辑,比如根据args[0](第一个参数)来决定数据源
        if ((Integer) args[0] % 2 == 0) return "primary";
        return "secondary";
    }
}
}

然后在你的服务中注入并设置这个Resolver:

@Autowired
public void setDataSourceLookup(DynamicDataSourceKeyResolver resolver) {
    ((AbstractRoutingDataSource) dataSource).setDefaultTargetDataSourceLookup(resolver);
}

这样,每次调用到数据源的地方,都会根据你的逻辑动态切换到不同的数据源。请注意,实际应用中策略需根据具体业务需求调整。

这些配置还是太复杂了,看下引入dynamic-datasource-spring-boot-starter

dynamic-datasource-spring-boot-starter 是一个简化Spring Boot应用中配置多数据源管理的开源库。它支持动态切换数据源,可以方便地处理读写分离、分库等场景。下面是引入并使用 dynamic-datasource-spring-boot-starter 的简化配置步骤:

1. 添加依赖首先,在你的Spring Boot项目的pom.xml或build.gradle文件中加入 dynamic-datasource-spring-boot-starter 的依赖。

Maven:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter
    <version>最新版本号</version>
</dependency>

2. YAML配置在application.yml文件中配置你的数据源,包括主数据源和其他数据源:

spring:
  datasource:
    dynamic:
      primary: master
      strict: false # 是否严格匹配数据源名称,默认false
      datasource:
        master:
          driver-class-name: oracle.jdbc.driver.OracleDriver
          url: jdbc:oracle:thin:@localhost:1521/orclpdb1
          username: system
          password: manager
        slave:
          driver-class-name: oracle.jdbc.driver.OracleDriver
          url: jdbc:oracle:thin:@localhost:15222/orclpdb2
          username: scott
          password: tiger

3. 使用多数据源在业务代码中,你可以通过@DS注解器来指定使用特定的数据源,或者不指定时使用默认的数据源。

3.1. 在Service或Repository中指定数据源

@Service
public class UserService {

    @DS("slave")
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // 业务逻辑...
}

3.2. 动态切换数据源在需要动态切换数据源的场景下,可以通过DynamicDataSourceContextHolder来实现。

public class SomeService {

    public void someMethodBasedOnCondition() {
        if (需要使用主数据源) {
            DataSourceContextHolder.setDataSourceType("master");
        } else {
            DataSourceContextHolder.setDataSourceType("slave");
        }

        // 执行数据库操作...

        DataSourceContextHolder.clearDataSourceType(); // 清除上下文,恢复默认数据源
    }
}
}

4. 自动配置切换策略dynamic-datasource-spring-boot-starter也支持自动路由策略,比如读写分离。

你可以配置master-slave来自动路由读写操作到主库,读操作到从库。

spring:
  datasource:
    dynamic:
      strategy: master-slave

之前的单数据源可以通过配置druid的属性:

connectionProperties: config.decrypt=true;config.decrypt.key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIRTeF9hVfHv0qiOpzgQYW0/oQk6sQp278uwtBONYj2cKqF2OcBD8...==
指定数据库敏感信息不对称加解密的公钥

但是换成多数据源后,并不会触发解密密码字段。

AI后面给出的两三个办法都是行不通的。。。。

当然,如果你的应用需要配置多个Druid数据源,并且每个数据源的密码都需要通过自定义的解密方法解密,你可以扩展上面的配置方法以适应多数据源的场景。以下是实现多个Druid数据源并共用同一解密方法的一个示例:自定义解密工具类(与单数据源时相同)

package com.example.utils;

import org.springframework.stereotype.Component;

@Component
public class EncryptionUtils {

    public String decrypt(String encryptedText) {
        // 实际解密逻辑
        return encryptedText; // 示例返回,实际应替换为解密后明文
    }
}
package com.example.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.example.utils.EncryptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class MultiDataSourceConfig {

    @Autowired
    private EncryptionUtils encryptionUtils;

    // 假设有两个数据源的配置类,你可以根据实际需要增加更多
    @ConstructorBinding
    @ConfigurationProperties(prefix = "spring.datasource.db1")
    public static class Db1DataSourceProperties {
        private String url;
        private String username;
        private String passwordEncrypted; // 加密的密码
        // getter & setter
    }

    @ConstructorBinding
    @ConfigurationProperties(prefix = "spring.datasource.db2")
    public static class Db2DataSourceProperties {
        private String url;
        private String username;
        private String passwordEncrypted; // 加密的密码
        // getter & setter
    }

    @Bean(name = "db1DataSource")
    public DataSource db1DataSource(Db1DataSourceProperties properties) {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(properties.getUrl());
        dataSource.setUsername(properties.getUsername());
        dataSource.setPassword(encryptionUtils.decrypt(properties.getPasswordEncrypted()));
        // 其他配置
        return dataSource;
    }

    @Bean(name = "db2DataSource")
    public DataSource db2DataSource(Db2DataSourceProperties properties) {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(properties.getUrl());
        dataSource.setUsername(properties.getUsername());
        dataSource.setPassword(encryptionUtils.decrypt(properties.getPasswordEncrypted()));
        // 其他配置
        return dataSource;
    }

    // 如果需要动态数据源路由,可参考dynamic-datasource-spring-boot-starter或自定义AbstractRoutingDataSource逻辑
}

按照网上的passwordCallback也是不行

最后是下面的方法搞定了:

Spring:
  datasource:
    dynamic:
      primary: master
      public-key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI....==
      datasource:
        master:
          url: jdbc:oracle:thin:@127.0.0.1:1521/abcd
          password: ENC(加密后密文2)
          username: ENC(加密后密文1)
        slave:
          url: jdbc:oracle:thin:@127.0.0.1/defg
          password: 不加密原文

      

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

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

相关文章

AttenFace一个基于人脸识别的实时考勤验证系统算法研究

0 、引言 论文提出了一个使用面部识别、允许实时监控考勤的考勤系统&#xff0c; 可以检查由于欺骗和遗漏造成的欺诈。 论文地址&#xff1a;https://arxiv.org/abs/2211.07582v1 1. 概述 在大学和其他机构的课堂上&#xff0c;通常会进行考勤。然而&#xff0c;这种方式往往…

工业互联网基本概念及关键技术(295页PPT)

资料介绍&#xff1a; 工业互联网的核心是通过工业互联网平台把设备、生产线、工厂、供应商、产品和客户紧密地连接融合起来。这种连接能够形成跨设备、跨系统、跨厂区、跨地区的互联互通&#xff0c;从而提高效率&#xff0c;推动整个制造服务体系智能化。同时&#xff0c;工…

2024最新华为OD机试-C/D卷 - 在线OJ使用说明

文章目录 &#x1fa90;在线 OJ 入口&#x1f3a7;申请OD使用权限&#x1f353;在线 OJ 的使用说明OJ主界面专题系列语言支持评测结果 &#x1fa90;在线 OJ 入口 &#x1f517; 2024最新华为OD机试 - 在线OJ入 &#x1f3a7;申请OD使用权限 本专栏配套 OJ 的为了配合考友更高…

git: 批量删除分支

环境&#xff1a; window11git version 2.42.0git-bash.exe window环境下&#xff1a; 1. 批量删除本地 git branch |grep xxx |xargs git branch -D比如&#xff1a; 想批量删除本地含有 release 关键字的分支&#xff1a; 2. 批量删除远程 git branch -r | grep xxxx | …

Qt for Android 申请摄像头权限

步骤 1. 添加用户权限 AndroidManifest.xml 中新增&#xff08;不添加后面申请选项时不弹窗&#xff09; 或者再Qt Creator中直接添加 2. Qt代码申请权限 Qt自己封装好了一些常用的权限申请&#xff0c; 详情Qt Assistant文档搜索 QPermission查看 #include <QPermi…

kafka-消费者组(SpringBoot整合Kafka)

文章目录 1、消费者组1.1、使用 efak 创建 主题 my_topic1 并建立6个分区并给每个分区建立3个副本1.2、创建生产者发送消息1.3、application.yml配置1.4、创建消费者监听器1.5、创建SpringBoot启动类1.6、屏蔽 kafka debug 日志 logback.xml1.7、引入spring-kafka依赖1.8、消费…

如何理解与学习数学分析——第二部分——数学分析中的基本概念——第7章——连续性

第2 部分&#xff1a;数学分析中的基本概念 (Concepts in Analysis) 7. 连续性(Continuity) 本章首先讨论连续性的直观概念&#xff0c;并介绍与早期数学中常见的函数不同的函数。解释了连续性的定义&#xff0c;并演示了如何使用它来证明函数在一点上连续&#xff0c;以及证…

K210视觉识别模块学习笔记5:(嘉楠)训练使用模型_识别人脸

今日开始学习K210视觉识别模块:(嘉楠)训练与使用模型_识别人脸 亚博智能的K210视觉识别模块...... 固件库版本: canmv_yahboom_v2.1.1.bin 之前的训练网址部署模型时需要我们自己更换固件&#xff0c;而且还不能用亚博的图像操作库函数了&#xff0c;这十分不友好&#xff0…

【Python系列】Python 方法变量参数详解

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

C++第二十四弹---从零开始模拟STL中的list(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1、基本结构 2、基本函数实现 2.1、默认构造函数 2.2、尾插数据 3、迭代器的封装 3.1、迭代器的基本结构 3.2、迭代器重载函数的实现 4、迭…

数字逻辑电路交通信号灯控制器设计与multisim仿真

当今时代是一个自动化时代,交通灯控制等很多行业的设备都与计算机密切相关。因此,一个好的交通灯控制系统,将给道路拥挤、违章控制等方面给技术革新。随着大规模的集成电路及计算机技术的迅速发展,以及人工智能在控制技术方面的广泛运用,智能设备有了很大的发展,是现在科…

基于ssm的乡村振兴战略下海东地区农产品购销系统

一、系统架构 前端&#xff1a;vue | element-ui 后端&#xff1a;spring | springmvc | mybatis 环境&#xff1a;jdk1.8 | mysql | maven | nodejs 二、代码及数据库 三、功能介绍 01. web端-首页1 02. web端-首页2 03. web端-登录 04. web端…

【数学建模】MATLAB入门教程:插值与拟合(下)

前言 插值与拟合在数据处理和科学计算中扮演着非常重要的角色&#xff0c;它们用于估算未知数据点的值&#xff0c;帮助我们理解和预测数据趋势 一、一维插值 1、一维插值定义 已知n1个节点(,)(j0,1,...,n,其中互不相同&#xff0c;不妨设a<<...<b),求任一插值点(…

网络安全领域六大顶级会议介绍:含会议介绍、会议地址及会议时间和截稿日期

**引言&#xff1a;**从事网络安全工作&#xff0c;以下六个顶会必须要知道&#xff0c;很多安全的前沿技术都会在如下会议中产生与公开&#xff0c;如下会议发表论文大部分可以公开下载。这些会议不仅是学术研究人员展示最新研究成果的平台&#xff0c;也是行业专家进行面对面…

chlarles抓包工具之---打断点

打断点的目的 通过打断点可以修改请求的数据或者响应&#xff0c;来测试各种场景 打断点流程 1、选中需要打断点的接口右键&#xff0c;选中Breakpoints 2、Proxy --> Breakpoint Setting 如果打断点一直进不去&#xff0c;把设置的query项清空

音频数据上的会话情感分析

情感分析&#xff0c;也被称为观点挖掘&#xff0c;是自然语言处理(NLP)中一个流行的任务,因为它有着广泛的工业应用。在专门将自然语言处理技术应用于文本数据的背景下,主要目标是训练出一个能够将给定文本分类到不同情感类别的模型。下图给出了情感分类器的高级概述。 例如,三…

【CTF Web】BUUCTF BUU LFI COURSE 1 Writeup(代码审计+PHP+文件包含漏洞)

BUU LFI COURSE 1 1 点击启动靶机。 解法 <?php /*** Created by PhpStorm.* User: jinzhao* Date: 2019/7/9* Time: 7:07 AM*/highlight_file(__FILE__);if(isset($_GET[file])) {$str $_GET[file];include $_GET[file]; }如果GET请求中接收到file参数&#xff0c;就会…

刷新方盒子最快10万销量纪录 捷途旅行者何以颠覆越野市场?

近年”方盒子“产品迅速崛起&#xff0c;在新一轮的市场角逐中&#xff0c;率先突围的并非传统豪强&#xff0c;而是首次进军越野市场的捷途汽车。作为“燃油车&#xff0c;”捷途旅行者&#xff0c;在面对纯电、混动等产品的强势围剿下&#xff0c;仅用时9个月便成为细分市场销…

Linux ip命令常用操作

ip 命令来自 iproute2 软件包&#xff0c;在 CentOS 7 中默认已安装&#xff08;yum install -y iproute&#xff09;。 iproute2 软件包提供了很多命令&#xff08;rpm -ql iproute |grep bin&#xff09;&#xff0c;如 ss 命令、bridge&#xff0c;这些命令可以完全替代 if…

Vue3 【实战】封装 useLocation

技术要点 通过 Vue3 的组合式API 仿写 react 中的 hook 代码实现 封装 hooks/useLocation.js import { reactive, onMounted, toRefs } from vue// 模拟异步获取 function getLocation(fail) {return new Promise((resolve) > {setTimeout(() > {if (fail) {// 模拟失败…