Springboot 프로젝트 가 Mysql 다 중 데이터 원본 전환 을 실현 하 는 완전한 실례

1.추상 적 인 라 우 팅 데이터 소스 추상 적 인 소스 코드 분석
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource 이하 변수 주목

@Nullable
private Map<Object, Object> targetDataSources; //      
@Nullable
private Object defaultTargetDataSource; //        
@Nullable
private Map<Object, DataSource> resolvedDataSources; //       
@Nullable
private DataSource resolvedDefaultDataSource; //         
이 두 그룹의 변 수 는 서로 대응 하 는 것 입 니 다.여러 개의 인 스 턴 스 데이터 소스 전환 코드 를 잘 알 고 있 을 때 여러 개의 데이터 소스 가 있 을 때 기본 데이터 소스 로 지정 해 야 합 니 다.
여기 서도 마찬가지 입 니 다.여러 데이터 원본 을 동시에 초기 화 할 때 setDefault TargetDataSource 방법 을 기본 데이터 원본 으로 지정 해 야 합 니 다.
우리 가 주목 해 야 할 것 은 맵targetDataSources 와 맵resolvedDataSources 입 니 다.
targetDataSources 는 외부 프로그램 에 노출 되 어 값 을 부여 하 는 것 이 고 resolvedDataSources 는 프로그램 내부 에서 실 행 될 때의 근거 이기 때문에 값 을 부여 하 는 작업 이 있 을 수 있 습 니 다.

이 소스 코드 를 통 해 알 수 있 듯 이 실행 할 때마다 targetDataSources 안의 모든 요 소 를 옮 겨 다 니 며 resolvedDataSources 에 값 을 부여 합 니 다.이렇게 하면 외부 프로그램 에 새로운 데이터 원본 을 추가 하면 내부 에 추가 하여 사용 하여 데이터 원본 의 동적 로드 를 실현 합 니 다.
이 추상 류 를 계승 할 때 추상 적 인 방법 을 실현 해 야 합 니 다.proctected abstract Object determineCurrentLookupkey().이 방법 은 어떤 데이터 원본 을 사용 해 야 하 는 지 지정 하 는 데 사 용 됩 니 다.
2.다 중 데이터 소스 전환 과 동적 데이터 소스 로드 실현
A-프로필 정보
application.yml 파일

server:
 port: 18080
spring:
 datasource:
 type: com.alibaba.druid.pool.DruidDataSource
 druid:
  #     
  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
  #     
  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-코딩 실현
1.DynamicDataSource 류 를 만 들 고 AbstractRoutingDataSource 추상 류 를 계승 하여 determineCurrentLookupkey 방법 을 실현 합 니 다.이 방법 을 통 해 현재 사용 하고 있 는 데이터 원본 을 지정 합 니 다.
2.DynamicDataSource 클래스 에서 ThreadLocal 을 통 해 전체 데이터 원본 이름 을 유지 하고 나중에 이 이름 을 수정 하여 동적 전환 을 실현 합 니 다.

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

/**
 * @ClassName DynamicDataSource
 * @Description        
 * @Author Josen
 * @Date 2020/11/5 14:28
 **/
public class DynamicDataSource extends AbstractRoutingDataSource {
 //   ThreadLocal         map           
 private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

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

 /**
  *           
  */
 @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.DynamicDataSourceConfig 류 를 만 들 고 application.yaml 설정 의 여러 데이터 소스 정 보 를 도입 하여 여러 데이터 소스 를 구축 합 니 다.

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        ,     
 * @Author Josen
 * @Date 2020/11/5 14:23
 **/
@Configuration
@Component
public class DynamicDataSourceConfig {
 /**
  *   application  ,  master-db   
  */
 @Bean
 @ConfigurationProperties("spring.datasource.druid.master-db")
 public DataSource myMasterDataSource(){
  return DruidDataSourceBuilder.create().build();
 }

 /**
  *   application  ,  slave-db   
  */
 @Bean
 @ConfigurationProperties("spring.datasource.druid.slave-db")
 public DataSource mySlaveDataSource(){
  return DruidDataSourceBuilder.create().build();
 }
 /**
  *   application  ,       
  */
 @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=     
  // targetDataSources=     (  )
  return new DynamicDataSource(myMasterDataSource, targetDataSources);
 }
}
4.MyDataSource 사용자 정의 주 해 를 만 들 고 후속 AOP 는 이 주 해 를 착안점 으로 하고 이 주 해 를 사용 하여 서로 다른 값 을 동적 으로 지정 한 데이터 원본 으로 전환 합 니 다.

import java.lang.annotation.*;
/**
 *         
 *          Service         ,       
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyDataSource {
 String name() default "";
}
5.DataSourceAspectAOP 절단면 류 를 만 들 고 MyDataSource 주 해 를 착안점 으로 확대 합 니 다.@MyDataSource 에 의 해 주석 이 들 어 오 는 방법 을 실행 할 때 이 주석 이 들 어 오 는 name 을 가 져 오고 지정 한 데이터 원본 으로 전환 하여 실행 합 니 다.실행 이 완료 되면 기본 데이터 원본 으로 전환 합 니 다.

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         around
  */
 @Pointcut("@annotation(com.josen.mydemo20201105.annotation.MyDataSource)")
 public void dataSourcePointCut() {
 }

 /**
  *     MyDataSource     ,       
  *     : (  &  &  &  )      ,            
  * @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,             
  MyDataSource dataSource = method.getAnnotation(MyDataSource.class);
  if(dataSource == null){
   // 1.1        
   DynamicDataSource.setDataSource("master-db");
  }else {
   // 1.2          
   DynamicDataSource.setDataSource(dataSource.name());
   logger.info("         =========>"+dataSource.name());
  }
  try {
   return point.proceed();
  } finally {
   //      -        
   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}) //           
@MapperScan(basePackages = "com.josen.mydemo.mapper")
public class MydemoApplication {
 public static void main(String[] args) {
  SpringApplication.run(MydemoApplication.class, args);
 }
}
7.여기까지 기본적으로 완성 되 었 고 나머지 는 데이터 원본 을 정확하게 전환 하 는 지 테스트 하 는 것 입 니 다.
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
public class PermissionService {
 @Autowired
 private PermissionMapper permissionMapper;
	//        
 @MyDataSource(name = "slave-db")
 public List<Permission> findSlaveAll(){
  return permissionMapper.findAll();
 }
	//      
 public List<Permission> findAll(){
  return permissionMapper.findAll();
 }
}
컨트롤 러 층

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

 //       master-db  
 @GetMapping("/master")
 public List<Permission> handlerFindAll() {
  List<Permission> list = permissionService.findAll();
  return list;
 }

 //       slave-db  
 @GetMapping("/slave")
 public List<Permission> handlerFindAll2() {
  List<Permission> list = permissionService.findSlaveAll();
  return list;
 }
}
C-테스트 데이터 원본 전환
Mysql 데이터


인터페이스 반환 데이터


데모 소스 주소:https://gitee.com/taco-gigigi/multiple-data-sources
총결산
Springboot 프로젝트 가 Mysql 다 중 데이터 원본 전환 을 실현 하 는 것 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 Springboot 프로젝트 Mysql 다 중 데이터 원본 전환 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 지원 바 랍 니 다!

좋은 웹페이지 즐겨찾기