软件编程
位置:首页>> 软件编程>> java编程>> Springboot整合多数据源代码示例详解

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

作者:william_zhao  发布时间:2022-03-31 07:48:59 

标签:spring,boot,整合,多,数据源

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

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

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

项目结构

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

下面上代码:

首先是依赖:


<!--数据库连接-->
   <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <scope>runtime</scope>
   </dependency>
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-jdbc</artifactId>
   </dependency>
   <!--sqlserver-->
   <dependency>
     <groupId>com.microsoft.sqlserver</groupId>
     <artifactId>mssql-jdbc</artifactId>
     <scope>runtime</scope>
   </dependency>
   <!--mybatis-plus-->
   <dependency>
     <groupId>com.baomidou</groupId>
     <artifactId>mybatis-plus-boot-starter</artifactId>
     <version>3.1.2</version>
   </dependency>
   <!--数据库连接池-->
   <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>druid</artifactId>
     <version>1.1.8</version>
   </dependency><!--AOP-->
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-aop</artifactId>
   </dependency>

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<String> contextHolder = new ThreadLocal<>();

public DynamicDataSource(DataSource defaultTargetDataSource, Map<String, DataSource> 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<String, DataSource> targetDataSources = new HashMap<>();
   targetDataSources.put(DataSourceNames.FIRST, firstDataSource);
   targetDataSources.put(DataSourceNames.SECOND, secondDataSource);
   return new DynamicDataSource(firstDataSource, targetDataSources);
 }

/**
  * mybatis-plus分页插件<br>
  * 文档:http://mp.baomidou.com<br>
  */
 @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整合多数据源代码示例详解

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

至此就整合完了

来源:https://www.cnblogs.com/wiliamzhao/p/13231663.html

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com