spring boot配置多数据源(静态和动态数据源)

news2024/11/27 16:37:27

背景

在开发过程中,很多时候都会有垮数据库操作数据的情况,需要同时配置多套数据源,即多个数据库,保证不同的业务在不同的数据库执行操作,通过mapper来灵活的切换数据源。
本文以sqlserver和mysql混合数据源配置为例。

配置多数据源方案

1、通过mapper配置数据源
2、配置动态数据源

具体实现

1)、 通过mapper配置数据源

(1)maven配置

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

(2)服务配置文件,application.yml

server:
  port: 9900
spring:
  datasource:
    db1:
      type: com.zaxxer.hikari.HikariDataSource
      driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
      jdbc-url: jdbc:sqlserver://localhost:10009;DatabaseName=test
      username: sa
      password: 654321



    db2:
      type: com.zaxxer.hikari.HikariDataSource
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/test2?useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&allowMultiQueries=true
      username: root
      password: 123456


(3)添加数据库配置

@Configuration
public class DataSourceConfig {

    @Bean(name = "maindb")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.db1")
    public DataSource businessDbDataSource() {
        return new HikariDataSource();
    }

    @Bean(name = "seconddb")
    @ConfigurationProperties(prefix = "spring.datasource.db2")
    public DataSource newhomeDbDataSource() {
        return new HikariDataSource();
    }
}

(4)单独配置每个数据源信息

注意:@Primary该注解理解为默认数据源

包路径配置可对比参考后面的项目结构截图

@Configuration
@MapperScan(basePackages = {"com.gxin.datasource.dao.maindb"}, sqlSessionFactoryRef = "sqlSessionFactoryMaindb")
public class DatasourceMainConfig {

    @Autowired
    @Qualifier("maindb")
    private DataSource dataSourceMaindb;

    @Bean
    @Primary
    public SqlSessionFactory sqlSessionFactoryMaindb() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSourceMaindb);
        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/maindb/*.xml"));
        // 打印sql日志
        // org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        // configuration.setLogImpl(StdOutImpl.class);
        // factoryBean.setConfiguration(configuration);
        return factoryBean.getObject();
    }

    @Bean
    @Primary
    public SqlSessionTemplate sqlSessionTemplateMaindb() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactoryMaindb());
    }
}
@Configuration
@MapperScan(basePackages = {"com.gxin.datasource.dao.seconddb"}, sqlSessionFactoryRef = "sqlSessionFactorySeconddb")
public class DatasourceSecondConfig {
    @Autowired
    @Qualifier("seconddb")
    private DataSource dataSourceSeconddb;

    @Bean
    public SqlSessionFactory sqlSessionFactorySeconddb() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSourceSeconddb);
        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/seconddb/*.xml"));
        // 打印sql日志
        // org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        // configuration.setLogImpl(StdOutImpl.class);
        // factoryBean.setConfiguration(configuration);
        return factoryBean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplateSeconddb() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactorySeconddb());
    }
}

(5)根据每个单独的数据源的配置信息搭建mapper接口和mapper.xml文件

(6)配置mapper多数据源完成,下图为完整的项目结构

2)、 配置动态数据源

(1)maven配置


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

(2)服务配置文件,application.yml

server:
  port: 9901
spring:
  main:
    allow-bean-definition-overriding: true
  datasource:
    db1:
      type: com.zaxxer.hikari.HikariDataSource
      driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
      jdbc-url: jdbc:sqlserver://localhost:10009;DatabaseName=test
      username: sa
      password: 654321



    db2:
      type: com.zaxxer.hikari.HikariDataSource
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/test2?useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&allowMultiQueries=true
      username: root
      password: 123456

(3)添加数据源列表

public interface DataSourceConstant {
    /**
     * 默认数据库
     */
    String MAIN = "MAIN";

    /**
     * 第二数据库
     */
    String SECOND = "SECOND";
}

(4)动态数据源数据库信息配置

@Configuration
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
public class DynamicDataSourceConfig {

    // 核心数据库
    @Bean(name = DataSourceConstant.MAIN)
    @ConfigurationProperties(prefix = "spring.datasource.db1")
    public DataSource getMAINDataSource() {
        return new HikariDataSource();
    }

    // 第二数据库
    @Bean(name = DataSourceConstant.SECOND)
    @ConfigurationProperties(prefix = "spring.datasource.db2")
    public DataSource getSECONDDataSource() {
        return new HikariDataSource();
    }

    @Bean
    @Primary
    public DataSource dynamicDataSource() {
        Map<Object, Object> dataSourceMap = new HashMap<>();
        dataSourceMap.put(DataSourceConstant.MAIN, getMAINDataSource());
        dataSourceMap.put(DataSourceConstant.SECOND, getSECONDDataSource());
        //设置动态数据源
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        dynamicDataSource.setDefaultTargetDataSource(getMAINDataSource());

        return dynamicDataSource;
    }
}

(5)添加动态数据源策略获取配置,继承AbstractRoutingDataSource

@Component
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        // 此处暂时返回固定 master 数据源, 后面按动态策略修改
        return DynamicDataSourceContextHolder.getContextKey();
    }
}

(6)数据源切换策略配置

public class DynamicDataSourceContextHolder {
    /**
     * 动态数据源名称上下文
     */
    private static final ThreadLocal<String> DATASOURCE_CONTEXT_KEY_HOLDER = new ThreadLocal<>();

    /**
     * 设置/切换数据源
     */
    public static void setContextKey(String key) {
        DATASOURCE_CONTEXT_KEY_HOLDER.set(key);
    }

    /**
     * 获取数据源名称
     */
    public static String getContextKey() {
        String key = DATASOURCE_CONTEXT_KEY_HOLDER.get();
        return key == null ? DataSourceConstant.MAIN : key;
    }

    /**
     * 删除当前数据源名称
     */
    public static void removeContextKey() {
        DATASOURCE_CONTEXT_KEY_HOLDER.remove();
    }
}

(6.1) 这里写掉了,补充数据库会话配置

@Configuration
public class SqlSessionConfig {
    @Autowired
    private DynamicDataSource source;

    public SqlSessionConfig() {
    }

    @Bean(name = {"sqlSessionFactoryBean"})
    public SqlSessionFactoryBean getSessionFactory() throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(this.source);
        factory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        // 打印sql日志
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setLogImpl(StdOutImpl.class);
        factory.setConfiguration(configuration);
        return factory;
    }

    @Bean(name = {"sqlSession"})
    public SqlSessionTemplate getSqlSession() throws Exception {
        return new SqlSessionTemplate(Objects.requireNonNull(getSessionFactory().getObject()));
        // SqlSessionFactory factory = this.getSessionFactory().getObject();
        // return new SqlSessionTemplate(factory, ExecutorType.BATCH);
    }

    @Bean
    public DataSourceTransactionManager getDataSourceTransaction() {
        DataSourceTransactionManager manager = new DataSourceTransactionManager();
        manager.setDataSource(this.source);
        return manager;
    }
}

(7) 添加切换数据源标识注解,默认为MAIN数据源

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DBS {

    /**
     * 数据源名称
     */
    String value() default DataSourceConstant.MAIN;
}

(8)通过配置的数据源标识注解,动态切换数据源

@Aspect
@Component
public class DynamicDataSourceAspect {

    @Pointcut("@annotation(com.gxin.dynamicdatasource.config.DBS)")
    public void dataSourcePointCut() {

    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String dsKey = getDSAnnotation(joinPoint).value();
        DynamicDataSourceContextHolder.setContextKey(dsKey);
        try {
            return joinPoint.proceed();
        } finally {
            DynamicDataSourceContextHolder.removeContextKey();
        }
    }

    /**
     * 根据类或方法获取数据源注解
     */
    private DBS getDSAnnotation(ProceedingJoinPoint joinPoint) {
        Class<?> targetClass = joinPoint.getTarget().getClass();
        DBS dsAnnotation = targetClass.getAnnotation(DBS.class);
        // 先判断类的注解,再判断方法注解
        if (Objects.nonNull(dsAnnotation)) {
            return dsAnnotation;
        } else {
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            return methodSignature.getMethod().getAnnotation(DBS.class);
        }
    }
}

(9)到此动态数据源配置完成,一下的为使用情况,需要使用哪个数据源添加注解配置即可

@Repository
public interface TestMapper {

    int getModelcount();

    @DBS(DataSourceConstant.SECOND)
    int getUsercount();

}

(10)service层

@Service
public class ServiceInfo {

    @Autowired
    private TestMapper mainMapper;


    public void datasource() {
        int modelcount = mainMapper.getModelcount();
        System.out.println(modelcount);

        int usercount = mainMapper.getUsercount();
        System.out.println(usercount);
    }
}

(11)mapper. xml结构目录

(12)完整的项目结构截图

收工图

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

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

相关文章

美团开放平台SDK自动生成技术与实践

总第549篇2023年 第001篇美团开放平台为整个美团提供了20业务场景的开放API&#xff0c;为了使开发者能够快速且安全的接入美团开放平台&#xff0c;美团开放平台提供了多种语言的SDK来提高开发者的接入效率。本文介绍了美团开放平台如何自动生成SDK代码的相关技术实现方案&…

【学习】深度强化学习、模型压缩

文章目录一、deep reinforcement learningPolicy-based Approach——Learning an Actor作为actor的神经网络small model网络可以被修剪一、deep reinforcement learning 强化学习场景 监督学习和强化学习之间&#xff1a; 训练一个聊天机器人-强化学习&#xff1a;让两个代…

基于c语言tftp服务器与客户端实现

开发环境&#xff1a;ubuntu 所用知识点&#xff1a;c&#xff0c;socket, tcp/ip协议 A)本实验主要实现tftp协议的服务器与客户端。 服务器实现功能有&#xff1a; 1)接收处理客户端请求&#xff0c;上传下下载文件 2)进行用户验证 3)对传输数据进行加密解密处理 4)生成日志文…

TensorRT学习笔记--Ubuntu20.04安装TensorRT 8.2.5

目录 前言 1--查看本机环境配置 2--下载并安装Tensor RT 3--实例测试 3-1--验证Onnx模型的可用性 3-2--将Onnx模型转换为推理引擎engine 3-3--基于Tensor RT使用engine模型进行推理 4--参考 前言 推荐结合官方文档 3.2.3节中的Tar File Installation安装教程进行安装&a…

【docker09】镜像发布到docker私有库

镜像发布到docker私有库 1.Docker Registry 官方Docker Hub地址:https://hub.docker.com/&#xff0c;中国大陆访问太慢&#xff0c;并且具有被阿里云取代的趋势&#xff0c;不太主流Dockerhub、阿里云这样的公共镜像仓库可能不太方便&#xff0c;涉及机密的公司不可能提供镜像…

PDF如何转换成excel文档?这个方法很实用

PDF如何转换成excel文档&#xff1f;PDF文件是我们经常使用的文件之一&#xff0c;我们在很多工作场景都能接触到PDF文件&#xff0c;不过PDF文件并不能适用于各种情况&#xff0c;比如我们想对文件内的数据进行更改&#xff0c;我们就需要把PDF文件转换成excel表格再进行修改&…

js 生成条形码

简介&#xff1a; 通过js生成条形码 效果展示&#xff1a; 示例代码&#xff1a; <!-- Created by IntelliJ IDEA. User: songsir Date: 2018/11/26 Time: 10:49 --> <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8&…

分享一下我3个月收割大厂offer的一些经验总结

前几天&#xff0c;有位老粉私信我&#xff0c;说看到某95后学弟晒出阿里P7的工资单&#xff0c;他是真酸了…想狠补下技术&#xff0c;努力冲一把大厂。 为了帮到他&#xff0c;也为了大家能在最短的时间内做面试复习&#xff0c;我把软件测试面试系列都汇总在这一篇文章了。…

对抗搜索 学习笔记

先来看一道有意思题 situation 大意&#xff1a; 两个人玩井字棋&#xff0c;要求把所有位置填满后结束游戏。一方希望两者的连起来的线之差最多&#xff0c;一方希望最少。现在给定初始局面&#xff08;已经存在一些棋子&#xff09;以及先手&#xff0c;求最后的两者的连起…

SAP FICO预制凭证界面隐藏过账按钮

会计凭证一旦过账了就不能再进行修改&#xff0c;但其也提供了类似国内财务软件同样的预制功能&#xff0c;预制凭证过账之前不会更新会计系统。预制凭证虽然不更新科目余额&#xff0c;但同样会生成凭证编号&#xff0c;其凭证内容可以随意更改&#xff0c;也可以删除。一旦过…

bios设置u盘启动重装系统教程

​如今&#xff0c;大部分人都会采用U盘启动盘装系统&#xff0c;而使用U盘装系统之前&#xff0c;有一个很重要的步骤&#xff0c;那就是设置U盘启动。大部分电脑都可以直接通过u盘启动快捷键来选择U盘启动&#xff0c;少部分电脑只能通过bios设置u盘为第一启动项。那么&#…

支付宝的架构

自 2008 年双 11 以来&#xff0c;在每年双 11 超大规模流量的冲击上&#xff0c;蚂蚁金服都会不断突破现有技术的极限。2010 年双 11 的支付峰值为 2 万笔/分钟&#xff0c;到 2017 年双 11 时这个数字变为了 25.6 万笔/秒。 2018 年双 11 的支付峰值为 48 万笔/秒&#xff0c…

log4j2的使用

Log4j2的使用 概述 Apache Log4j 2是对Log4j的升级版&#xff0c;参考了logback的一些优秀的设计&#xff0c;并且修复了一些问题&#xff0c;因此带来了一些重大的提升&#xff0c;主要有&#xff1a; 异常处理&#xff0c;在logback中&#xff0c;Appender中的异常不会被应…

若依 ruoyi 配置多数据源 生成代码 导出代码

本文相关库说明&#xff1a;vue&#xff08;若依自带库&#xff09;db_game多数据源从库1db_paystore 多数据源从库2多数据源的情况下&#xff0c;想生成其他从库下数据库表对应的代码&#xff0c;但是若依自带的导入表中 是不会查询到从库各数据表信息的(只查询到若依框架对应…

我是这样解决 HBuilderX 安卓基座安装失败的问题

本文简介 点赞 关注 收藏 学会了 记录一个在使用 HBuilderX 开发 App 时遇到的问题。 同步资源失败&#xff0c;未得到同步资源的授权&#xff0c;请停止运行后重新运行&#xff0c;并注意手机上的授权提示 出现这个问题的原因是我把手机的 HBuilder App 给删掉了&#xff…

【自学Java】Java多维数组

Java多维数组 Java多维数组教程 Java 语言 中有 一维数组&#xff0c;也会有多维数组。如果有一个二维数组&#xff0c;那么数组的每个元素将会是一维数组&#xff0c;而不是单纯的元素。如果是一个多维数组&#xff0c;那么每个位置上面对应的是 纬度 - 1 的数组。 因为在平…

从官方文档学习Rabbit与SpringAMQP-乱版

本文也是笔者一直没有去详细学习的一个重要知识点MQ&#xff0c;也是架构中非常重要的一个中间件。 主要从Rabbit官网于Spring AMQP官方文档的角度去详细学习MQ 官方文档 Rabbit Spring AMQP 学习结果 测试项目地址 导读 本文主要从以下两个角度去学习MQ 一、RabbitMQ 官…

【nodejs】模块的加载机制

1、优先从缓存中加载 模块在第一次加载后会被缓存。意味着多次调用require()不会导致模块的代码被执行多次 注意&#xff1a;不论是内置模块、用户自定义模块、还是第三方模块&#xff0c;它们都会优先从缓存中加载&#xff0c;从而提高模块的加载效率。 &#xff08;1&#x…

【求证】 网上配镜靠谱吗?

肯定也有不少的小伙伴 看着网上琳琅满目的“明星同款”眼镜 心动不已 盘算着给自己弄一副“性价比” 最高“明星同款”那么网上配镜究竟靠不靠谱&#xff1f; 潍坊眼科医院眼健康管理中心提醒您 网上配镜需谨慎 网络平台的价格优势非常明显&#xff0c;部分销量高的店铺&#x…

二叉树基础计算

题目专题二叉树节点个数二叉树叶子节点个数二叉树第k 层节点个数二叉树查找值为x 的节点一共有这么几个题目&#xff0c;主要是用来表现题目的性质 分别是求 二叉树节点个数 二叉树叶子节点个数 二叉树第k 层节点个数 二叉树查找值为x 的节点 如果我使用的还是这个二叉树 其…