热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Springboot整合多数据源代码示例详解

最近有个老项目想逐步将新业务的数据放到新的数据库,以前的业务还得连接以前的数据库,于是需要整合多数据源。多数据源实际上是继承了AbstractRouting

最近有个老项目想逐步将新业务的数据放到新的数据库,以前的业务还得连接以前的数据库,于是需要整合多数据源 。

多数据源实际上是继承了AbstractRoutingDataSource类,这个类最终实现了DataSource接口,DataSource里只有一个getConnection方法,数据库每次访问的时候都要先通过这个方法获取连接,所有多数据源就是每次访问数据库之前动态的改变数据源。

在请求前改变数据源当然需要用到SpringAOP,自定义注解操作

项目结构

Springboot整合多数据源代码示例详解

下面上代码:

首先是依赖:


    
      mysql
      mysql-connector-java
      runtime
    
    
      org.springframework.boot
      spring-boot-starter-jdbc
    
    
    
      com.microsoft.sqlserver
      mssql-jdbc
      runtime
    
    
    
      com.baomidou
      mybatis-plus-boot-starter
      3.1.2
    
    
    
      com.alibaba
      druid
      1.1.8
          
    
      org.springframework.boot
      spring-boot-starter-aop
    

yml配置数据源

server:
 port: 8888

spring:
 jackson:
  time-zone: GMT+8
  date-format: yyyy-MM-dd HH:mm:ss
 datasource:
  druid:
   first:
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    jdbc-url: jdbc:mysql://rm-uf6265pj340sc9447oo.mysql.rds.54565.com:3306/dm?serverTimezOne=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=utf-8
    username: username
    password: password
   second:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
    jdbc-url: jdbc:sqlserver://39.104.203.222:1433;DatabaseName=TestTLcom
    username: root
    password: 123456

mybatis-plus:
 mapper-locations: classpath*:/mapper/*Mapper.xml
 type-aliases-package: com.zdyl.dynamicdatasourcedemo.entity
 global-config:
  #主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
  id-type: 3
  #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
  field-strategy: 2
  #驼峰下划线转换
  db-column-underline: true
  #刷新mapper 调试神器
  refresh-mapper: true
  #数据库大写下划线转换
  #capital-mode: true
  #序列接口实现类配置
  #key-generator: com.baomidou.springboot.xxx
  #逻辑删除配置
  #logic-delete-value: 0
  #logic-not-delete-value: 1
  #自定义填充策略接口实现
  #meta-object-handler: com.baomidou.springboot.xxx
  #自定义SQL注入器
  #sql-injector: com.baomidou.springboot.xxx
 configuration:
  map-underscore-to-camel-case: true
  cache-enabled: false

定义数据库名称

/**
 * 数据库名称
 */
public interface DataSourceNames {

  String FIRST = "first";
  String SECOnD= "second";
}

动态数据源

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 动态数据源
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

  private static final ThreadLocal cOntextHolder= new ThreadLocal<>();

  public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) {

    super.setDefaultTargetDataSource(defaultTargetDataSource);
    super.setTargetDataSources(new HashMap<>(targetDataSources));
    super.afterPropertiesSet();
  }

  @Override
  protected Object determineCurrentLookupKey() {
    return getDataSource();
  }

  public static String getDataSource() {
    return contextHolder.get();
  }

  public static void setDataSource(String dataSource) {
    contextHolder.set(dataSource);
  }

  public static void clearDataSource() {
    contextHolder.remove();
  }
}

配置多数据源

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.zdyl.dynamicdatasourcedemo.dynamicdatasource.DataSourceNames;
import com.zdyl.dynamicdatasourcedemo.dynamicdatasource.DynamicDataSource;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
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.HashMap;
import java.util.Map;

/**
 * 多数据源配置
 */
@Configuration
@MapperScan("com.zdyl.dynamicdatasourcedemo.**.mapper*")
public class MybatisPluConfig {

  /**
   * 数据源配置
   * @return
   */
  @Bean
  @ConfigurationProperties(prefix="spring.datasource.druid.first")
  public DataSource firstDataSource() {
    return DataSourceBuilder.create().build();
  }

  @Bean
  @ConfigurationProperties(prefix="spring.datasource.druid.second")
  public DataSource secondDataSource() {
    return DataSourceBuilder.create().build();
  }

  @Bean
  @Primary
  public DynamicDataSource dataSource(DataSource firstDataSource, DataSource secondDataSource){
    Map targetDataSources = new HashMap<>();
    targetDataSources.put(DataSourceNames.FIRST, firstDataSource);
    targetDataSources.put(DataSourceNames.SECOND, secondDataSource);
    return new DynamicDataSource(firstDataSource, targetDataSources);
  }

  /**
   * mybatis-plus分页插件
* 文档:http://mp.baomidou.com
*/ @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } }

下面就是自定义注解

import java.lang.annotation.*;

/**
 * 多数据源注解
 * AOP拦截此注解更换数据源
 */

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CurDataSource {

  String name() default "";
}

AOP

import com.zdyl.dynamicdatasourcedemo.dynamicdatasource.DataSourceNames;
import com.zdyl.dynamicdatasourcedemo.dynamicdatasource.DynamicDataSource;
import com.zdyl.dynamicdatasourcedemo.dynamicdatasource.annotation.CurDataSource;
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.Ordered;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;


/**
 * 多数据源,切面处理类
 * AOP拦截多数据源注解 @CurDataSource 注解更换数据源
 */

@Slf4j
@Aspect
@Component
public class DataSourceAspect implements Ordered {


  /**
   * 切点
   */
  @Pointcut("@annotation(com.zdyl.dynamicdatasourcedemo.dynamicdatasource.annotation.CurDataSource)")
  public void dataSourcePointCut() {

  }

  @Around("dataSourcePointCut()")
  public Object around(ProceedingJoinPoint point) throws Throwable {
    MethodSignature signature = (MethodSignature) point.getSignature();
    Method method = signature.getMethod();
    CurDataSource curDataSource = method.getAnnotation(CurDataSource.class);
    if (curDataSource == null) {
      DynamicDataSource.setDataSource(DataSourceNames.FIRST);
      log.info("set datasource is " + DataSourceNames.FIRST);
    } else {
      DynamicDataSource.setDataSource(curDataSource.name());
      log.info("set datasource is " + curDataSource.name());
    }
    try {
      return point.proceed();
    } finally {
      DynamicDataSource.clearDataSource();
      log.info("clean datasource");
    }
  }

  @Override
  public int getOrder() {
    return 1;
  }
}

最后主启动了去掉数据源自动加载

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

最后我们来跑起来请求一下,测试一下是否正确

@RestController
public class CfgDeviceController {
  @Resource
  CfgDeviceService cfgDeviceService;
  @Resource
  CfgChargeStartInfoService cfgChargeStartInfoService;
  
  @CurDataSource(name = DataSourceNames.FIRST)
  @GetMapping("/test")
  public void getUser() {
    CfgDevice byId = cfgDeviceService.getById(19);
    System.out.println(byId.toString());
  }

  @CurDataSource(name = DataSourceNames.SECOND)
  @GetMapping("/test1")
  public void getUser1() {
    CfgChargeStartInfo byId = cfgChargeStartInfoService.getById(1);
    System.out.println(byId.toString());
  }
}

Springboot整合多数据源代码示例详解

**如果不加注解,使用默认数据源

至此就整合完了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程笔记。


推荐阅读
  • 开发笔记:MyBatis学习之逆向工程
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了MyBatis学习之逆向工程相关的知识,希望对你有一定的参考价值。转载:http://w ... [详细]
  • Java操作MySQL,创建JDBC工具类、使用Druid连接池技术,实现CRUD(增、删、改、查)
    要求:使用JDBC创建一张表,表名student,字段包含id,姓名(username)、班级(class_and_grad ... [详细]
  • kettle 8.3 连接mysql8.0.30 的入坑体验
      写这个东西主要是想吐槽为主,真的无语了。  kettle是java写的java版权是oracle的。mysql是Oracle的。   吐槽:  一般来说,在kettle中新建m ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • Python操作MySQL(pymysql模块)详解及示例代码
    本文介绍了使用Python操作MySQL数据库的方法,详细讲解了pymysql模块的安装和连接MySQL数据库的步骤,并提供了示例代码。内容涵盖了创建表、插入数据、查询数据等操作,帮助读者快速掌握Python操作MySQL的技巧。 ... [详细]
  • Tomcat安装与配置教程及常见问题解决方法
    本文介绍了Tomcat的安装与配置教程,包括jdk版本的选择、域名解析、war文件的部署和访问、常见问题的解决方法等。其中涉及到的问题包括403问题、数据库连接问题、1130错误、2003错误、Java Runtime版本不兼容问题以及502错误等。最后还提到了项目的前后端连接代码的配置。通过本文的指导,读者可以顺利完成Tomcat的安装与配置,并解决常见的问题。 ... [详细]
  • 在开发中,有时候一个业务上要求的原子操作不仅仅包括数据库,还可能涉及外部接口或者消息队列。此时,传统的数据库事务无法满足需求。本文介绍了Java中如何利用java.lang.Runtime.addShutdownHook方法来保证业务线程的完整性。通过添加钩子,在程序退出时触发钩子,可以执行一些操作,如循环检查某个线程的状态,直到业务线程正常退出,再结束钩子程序。例子程序展示了如何利用钩子来保证业务线程的完整性。 ... [详细]
  • 初识java关于JDK、JRE、JVM 了解一下 ... [详细]
  • 定义函数functionf(){}调用函数f();可变函数functionf(){}$f1f;$f1();匿名函数$ffunction($ ... [详细]
  • 关于java转换cst的信息
    本文目录一览:1、java之中SatSep1121:50:00CST2010 ... [详细]
  • 谈谈javascript中的日期Date对象详解编程语言
    一、日期对象  在javascript中并没有日期型的数据类型,但是提供了一个日期对象可以操作日期和时间。  日期对象的创建:  newDate();二、将日期对象转换为字符串   ... [详细]
  • jdbc通过idea连接mysql数据库(代码连接,不是插件),使用上海时区还是报错,使用UTCHAI还是报错
    出现时区问题,修改上海时区还有其他时区还是报错;其实我也很疑惑,为什么别人跟我用的是一样的代码,一样的软件,一 ... [详细]
author-avatar
傻瓜老公想你_633
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有