欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Springboot項目實現(xiàn)Mysql多數(shù)據(jù)源切換的完整實例

 更新時間:2020年11月06日 09:39:00   作者:迪迦Monster  
這篇文章主要給大家介紹了關于Springboot項目實現(xiàn)Mysql多數(shù)據(jù)源切換的完整實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

一、分析AbstractRoutingDataSource抽象類源碼

關注import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource以下變量

@Nullable
private Map<Object, Object> targetDataSources; // 目標數(shù)據(jù)源
@Nullable
private Object defaultTargetDataSource; // 默認目標數(shù)據(jù)源
@Nullable
private Map<Object, DataSource> resolvedDataSources; // 解析的數(shù)據(jù)源
@Nullable
private DataSource resolvedDefaultDataSource; // 解析的默認數(shù)據(jù)源

這兩組變量是相互對應的,在熟悉多實例數(shù)據(jù)源切換代碼的不難發(fā)現(xiàn),當有多個數(shù)據(jù)源的時候,一定要指定一個作為默認的數(shù)據(jù)源;

在這里也同理,當同時初始化多個數(shù)據(jù)源的時候,需要顯式的調用setDefaultTargetDataSource方法指定一個作為默認數(shù)據(jù)源;

我們需要關注的是Map<Object, Object> targetDataSources和Map<Object, DataSource> resolvedDataSources;

targetDataSources是暴露給外部程序用來賦值的,而resolvedDataSources是程序內部執(zhí)行時的依據(jù),因此會有一個賦值的操作;

根據(jù)這段源碼可以看出,每次執(zhí)行時,都會遍歷targetDataSources內的所有元素并賦值給resolvedDataSources;這樣如果我們在外部程序新增一個新的數(shù)據(jù)源,都會添加到內部使用,從而實現(xiàn)數(shù)據(jù)源的動態(tài)加載。
繼承該抽象類的時候,必須實現(xiàn)一個抽象方法:protected abstract Object determineCurrentLookupKey(),該方法用于指定到底需要使用哪一個數(shù)據(jù)源。

二、實現(xiàn)多數(shù)據(jù)源切換和動態(tài)數(shù)據(jù)源加載

A - 配置文件信息

application.yml文件

server:
 port: 18080
spring:
 datasource:
 type: com.alibaba.druid.pool.DruidDataSource
 druid:
  # 主數(shù)據(jù)源
  master-db:
  driverClassName: com.mysql.jdbc.Driver
  url: jdbc:mysql://192.168.223.129:13306/test_master_db?characterEncoding=utf-8
  username: josen
  password: josen
  # 從數(shù)據(jù)源
  slave-db:
  driverClassName: com.mysql.jdbc.Driver
  url: jdbc:mysql://192.168.223.129:13306/test_slave_db?characterEncoding=utf-8
  username: josen
  password: josen
mybatis:
 mapper-locations: classpath:mapper/*.xml
logging:
 path: ./logs/mydemo20201105.log
 level:
 com.josen.mydemo20201105: debug

maven 依賴

<dependencies>
 <!-- AOP -->
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
 </dependency>
 <!-- druid -->
 <dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid-spring-boot-starter</artifactId>
  <version>1.1.10</version>
 </dependency>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>2.1.3</version>
 </dependency>
 <dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <scope>runtime</scope>
 </dependency>
 <dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
 </dependency>
</dependencies>

B - 編碼實現(xiàn)

1、創(chuàng)建一個DynamicDataSource類,繼承AbstractRoutingDataSource抽象類,實現(xiàn)determineCurrentLookupKey方法,通過該方法指定當前使用哪個數(shù)據(jù)源;

2、 在DynamicDataSource類中通過ThreadLocal維護一個全局數(shù)據(jù)源名稱,后續(xù)通過修改該名稱實現(xiàn)動態(tài)切換;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.Map;

/**
 * @ClassName DynamicDataSource
 * @Description 設置動態(tài)數(shù)據(jù)源
 * @Author Josen
 * @Date 2020/11/5 14:28
 **/
public class DynamicDataSource extends AbstractRoutingDataSource {
 // 通過ThreadLocal維護一個全局唯一的map來實現(xiàn)數(shù)據(jù)源的動態(tài)切換
 private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

 public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
  super.setDefaultTargetDataSource(defaultTargetDataSource);
  super.setTargetDataSources(targetDataSources);
  super.afterPropertiesSet();
 }

 /**
  * 指定使用哪一個數(shù)據(jù)源
  */
 @Override
 protected Object determineCurrentLookupKey() {
  return getDataSource();
 }

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

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

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

3、創(chuàng)建DynamicDataSourceConfig類,引入application.yaml配置的多個數(shù)據(jù)源信息,構建多個數(shù)據(jù)源;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
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 org.springframework.stereotype.Component;

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

/**
 * @ClassName DynamicDataSourceConfig
 * @Description 引入動態(tài)數(shù)據(jù)源,構建數(shù)據(jù)源
 * @Author Josen
 * @Date 2020/11/5 14:23
 **/
@Configuration
@Component
public class DynamicDataSourceConfig {
 /**
  * 讀取application配置,構建master-db數(shù)據(jù)源
  */
 @Bean
 @ConfigurationProperties("spring.datasource.druid.master-db")
 public DataSource myMasterDataSource(){
  return DruidDataSourceBuilder.create().build();
 }

 /**
  * 讀取application配置,構建slave-db數(shù)據(jù)源
  */
 @Bean
 @ConfigurationProperties("spring.datasource.druid.slave-db")
 public DataSource mySlaveDataSource(){
  return DruidDataSourceBuilder.create().build();
 }
 /**
  * 讀取application配置,創(chuàng)建動態(tài)數(shù)據(jù)源
  */
 @Bean
 @Primary
 public DynamicDataSource dataSource(DataSource myMasterDataSource, DataSource mySlaveDataSource) {
  Map<Object, Object> targetDataSources = new HashMap<>();
  targetDataSources.put("master-db",myMasterDataSource);
  targetDataSources.put("slave-db", mySlaveDataSource);
  // myMasterDataSource=默認數(shù)據(jù)源
  // targetDataSources=目標數(shù)據(jù)源(多個)
  return new DynamicDataSource(myMasterDataSource, targetDataSources);
 }
}

4、 創(chuàng)建MyDataSource自定義注解,后續(xù)AOP通過該注解作為切入點,通過獲取使用該注解存入不同的值動態(tài)切換指定的數(shù)據(jù)源;

import java.lang.annotation.*;
/**
 * 自定義數(shù)據(jù)源注解
 * 在需要切換數(shù)據(jù)源的Service層方法上添加此注解,指定數(shù)據(jù)源名稱
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyDataSource {
 String name() default "";
}

5、 創(chuàng)建DataSourceAspectAOP切面類,以MyDataSource注解為切入點作拓展。在執(zhí)行被@MyDataSource注解的方法時,獲取該注解傳入的name,并切換到指定數(shù)據(jù)源執(zhí)行,執(zhí)行完成后切換回默認數(shù)據(jù)源;

import com.josen.mydemo20201105.annotation.MyDataSource;
import com.josen.mydemo20201105.datasource.DynamicDataSource;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.lang.reflect.Method;

/**
 * @ClassName DataSourceAspect
 * @Description Aop切面類配置
 * @Author Josen
 * @Date 2020/11/5 14:35
 **/
@Aspect
@Component
@Slf4j
public class DataSourceAspect {
 private static final Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);

 /**
  * 設置切入點
  * 只有調用@MyDataSource注解的方法才會觸發(fā)around
  */
 @Pointcut("@annotation(com.josen.mydemo20201105.annotation.MyDataSource)")
 public void dataSourcePointCut() {
 }

 /**
  * 截取使用MyDataSource注解的方法,切換指定數(shù)據(jù)源
  * 環(huán)繞切面:是(前置&后置&返回&異常)通知的結合體,更像是動態(tài)代理的整個過程
  * @param point
  */
 @Around("dataSourcePointCut()")
 public Object around(ProceedingJoinPoint point) throws Throwable {
  MethodSignature signature = (MethodSignature) point.getSignature();
  Method method = signature.getMethod();
  logger.info("execute DataSourceAspect around=========>"+method.getName());
  // 1. 獲取自定義注解MyDataSource,查看是否配置指定數(shù)據(jù)源名稱
  MyDataSource dataSource = method.getAnnotation(MyDataSource.class);
  if(dataSource == null){
   // 1.1 使用默認數(shù)據(jù)源
   DynamicDataSource.setDataSource("master-db");
  }else {
   // 1.2 使用指定名稱數(shù)據(jù)源
   DynamicDataSource.setDataSource(dataSource.name());
   logger.info("使用指定名稱數(shù)據(jù)源=========>"+dataSource.name());
  }
  try {
   return point.proceed();
  } finally {
   // 后置處理 - 恢復默認數(shù)據(jù)源
   DynamicDataSource.clearDataSource();
  }
 }
}

6、 配置啟動類

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class}) // 不加載默認數(shù)據(jù)源配置
@MapperScan(basePackages = "com.josen.mydemo.mapper")
public class MydemoApplication {
 public static void main(String[] args) {
  SpringApplication.run(MydemoApplication.class, args);
 }
}

7、 到這里基本上已經完成,剩下的就是測試是否正確切換數(shù)據(jù)源了;

Mapper層

@Repository
public interface PermissionMapper {
 List<Permission> findAll();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.josen.mydemo.mapper.PermissionMapper">
 <select id="findAll" resultType="com.josen.mydemo20201105.pojo.Permission">
  select * from t_permission;
 </select>
</mapper>

Service層

@Service
public class PermissionService {
 @Autowired
 private PermissionMapper permissionMapper;
	// 切換從庫數(shù)據(jù)源
 @MyDataSource(name = "slave-db")
 public List<Permission> findSlaveAll(){
  return permissionMapper.findAll();
 }
	// 默認數(shù)據(jù)源
 public List<Permission> findAll(){
  return permissionMapper.findAll();
 }
}

Controller層

@RestController
@RequestMapping("/permission")
public class PermissionController {
 @Autowired
 private PermissionService permissionService;

 // 測試獲取默認master-db數(shù)據(jù)
 @GetMapping("/master")
 public List<Permission> handlerFindAll() {
  List<Permission> list = permissionService.findAll();
  return list;
 }

 // 測試獲取指定slave-db數(shù)據(jù)
 @GetMapping("/slave")
 public List<Permission> handlerFindAll2() {
  List<Permission> list = permissionService.findSlaveAll();
  return list;
 }
}

C - 測試數(shù)據(jù)源切換

Mysql數(shù)據(jù)

接口返回數(shù)據(jù)

Demo源碼地址:https://gitee.com/taco-gigigi/multiple-data-sources

總結

到此這篇關于Springboot項目實現(xiàn)Mysql多數(shù)據(jù)源切換的文章就介紹到這了,更多相關Springboot項目Mysql多數(shù)據(jù)源切換內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 基于MyBatis的數(shù)據(jù)持久化框架的使用詳解

    基于MyBatis的數(shù)據(jù)持久化框架的使用詳解

    Mybatis是一個優(yōu)秀的開源、輕量級持久層框架,它對JDBC操作數(shù)據(jù)庫的過程進行封裝。本文將為大家講解一下基于MyBatis的數(shù)據(jù)持久化框架的使用,感興趣的可以了解一下
    2022-08-08
  • SpringBoot如何讀取war包jar包和Resource資源

    SpringBoot如何讀取war包jar包和Resource資源

    這篇文章主要介紹了SpringBoot如何讀取war包jar包和Resource資源,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • Spring整合多數(shù)據(jù)源實現(xiàn)動態(tài)切換的實例講解

    Spring整合多數(shù)據(jù)源實現(xiàn)動態(tài)切換的實例講解

    下面小編就為大家?guī)硪黄猄pring整合多數(shù)據(jù)源實現(xiàn)動態(tài)切換的實例講解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • AsyncHttpClient?RequestFilter請求篩選源碼解讀

    AsyncHttpClient?RequestFilter請求篩選源碼解讀

    這篇文章主要為大家介紹了AsyncHttpClient?RequestFilter請求篩選源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • 詳解Eclipse 字體、字號的設置、最佳字體推薦

    詳解Eclipse 字體、字號的設置、最佳字體推薦

    這篇文章主要介紹了Eclipse 字體、字號的設置、最佳字體推薦,需要的朋友可以參考下
    2020-09-09
  • java9學習系列之安裝與jshell使用

    java9學習系列之安裝與jshell使用

    2017年9月21日,千呼萬喚始出來,Java9終于發(fā)布了。作為自己天天接觸的“對象”,還是應該多花點心思去了解她。后續(xù)再進一步了解詳細特性。下面這篇文章主要給大家介紹了關于java9學習系列之安裝與jshell使用的相關資料,需要的朋友可以參考下。
    2017-09-09
  • 一文帶你掌握Java8強大的StreamAPI

    一文帶你掌握Java8強大的StreamAPI

    Java8API添加了一個新的抽象稱為流Stream,可以讓你以一種聲明的方式處理數(shù)據(jù)。Stream 使用一種類似用SQL 語句從數(shù)據(jù)庫查詢數(shù)據(jù)的直觀方式來提供一種對 Java 集合運算和表達的高階抽象。Stream API可以極大提高Java程序員的生產力,讓程序員寫出高效率、干凈、簡潔的代碼
    2021-10-10
  • springboot使用war包部署到外部tomcat過程解析

    springboot使用war包部署到外部tomcat過程解析

    這篇文章主要介紹了springboot使用war包部署到外部tomcat過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • ShardingSphere jdbc集成多數(shù)據(jù)源的實現(xiàn)步驟

    ShardingSphere jdbc集成多數(shù)據(jù)源的實現(xiàn)步驟

    本文主要介紹了ShardingSphere jdbc集成多數(shù)據(jù)源的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Java was started but returned exit code=13問題解決案例詳解

    Java was started but returned exit code=13問題解決案例詳解

    這篇文章主要介紹了Java was started but returned exit code=13問題解決案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
    2021-09-09

最新評論