SpringBoot多數(shù)據(jù)源配置

SpringBoot 2.0+ 開(kāi)始推 HikariCP ,將默認(rèn)的數(shù)據(jù)庫(kù)連接池從 tomcat jdbc pool 改為了 hikari , HikariCP 在性能和并發(fā)方面表現(xiàn)更好一些

yml配置:

#數(shù)據(jù)源配置
 datasource:
   dsa:
     driver-class-name: com.sybase.jdbc4.jdbc.SybDataSource
     jdbc-url: jdbc:sybase:Tds:127.0.0.1:5127/test
     type: com.zaxxer.hikari.HikariDataSource
     username: root
     password: root
   dsb:
     driver-class-name: com.sybase.jdbc4.jdbc.SybDataSource
     jdbc-url: jdbc:sybase:Tds:127.0.0.1:5127/test
     type: com.zaxxer.hikari.HikariDataSource
     username: root
     password: root

com.zaxxer.hikari.HikariDataSource 包為mybatis自帶
導(dǎo)入以下依賴(lài)
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>

1.創(chuàng)建DBProperties



import com.zaxxer.hikari.HikariDataSource;

import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.stereotype.Component;

/**

* 實(shí)際數(shù)據(jù)源配置

*/

@Component

@Data

@ConfigurationProperties(prefix ="spring.datasource")

public class DBProperties {

private HikariDataSourcedsa;

 private HikariDataSourcedsc;

 private HikariDataSourcedsb;

}

2.創(chuàng)建dataSource

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import org.springframework.scheduling.annotation.EnableScheduling;

import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

import java.util.HashMap;

import java.util.Map;

/**

* 數(shù)據(jù)源配置

*/

@Configuration

@EnableScheduling

@Slf4j

public class DataSourceConfig {

@Autowired

  private DBPropertiesproperties;

  @Bean(name ="dataSource")

public DataSourcedataSource() {

//按照目標(biāo)數(shù)據(jù)源名稱(chēng)和目標(biāo)數(shù)據(jù)源對(duì)象的映射存放在Map中

      Map targetDataSources =new HashMap<>();

      targetDataSources.put("dsa", properties.getDsa());

      targetDataSources.put("dsb", properties.getDsb());

      targetDataSources.put("dsc", properties.getDsc());

      //采用是想AbstractRoutingDataSource的對(duì)象包裝多數(shù)據(jù)源

      DynamicDataSource dataSource =new DynamicDataSource();

      dataSource.setTargetDataSources(targetDataSources);

      dataSource.setDefaultTargetDataSource(properties.getDsb());

      return dataSource;

  }

@Bean

  public PlatformTransactionManagertxManager() {

return new DataSourceTransactionManager(dataSource());

  }

}

3.創(chuàng)建DynamicDataSource

import lombok.extern.slf4j.Slf4j;

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

/**

* 動(dòng)態(tài)數(shù)據(jù)源實(shí)現(xiàn)類(lèi)

*/

@Slf4j

public class DynamicDataSourceextends AbstractRoutingDataSource {

//數(shù)據(jù)源路由,此方用于產(chǎn)生要選取的數(shù)據(jù)源邏輯名稱(chēng)

  @Override

  protected ObjectdetermineCurrentLookupKey() {

//從共享線程中獲取數(shù)據(jù)源名稱(chēng)

      return DynamicDataSourceHolder.getDataSource();

  }

}

4.創(chuàng)建DynamicDataSourceHolder

/**

* 動(dòng)態(tài)數(shù)據(jù)源持有者,負(fù)責(zé)利用ThreadLocal存取數(shù)據(jù)源名稱(chēng)

*/

public class DynamicDataSourceHolder {

/**

* 本地線程共享對(duì)象

*/

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

  public static void putDataSource(String name) {

THREAD_LOCAL.set(name);

  }

public static StringgetDataSource() {

return THREAD_LOCAL.get();

  }

public static void removeDataSource() {

THREAD_LOCAL.remove();

  }

}

5.創(chuàng)建TargetDataSource

import java.lang.annotation.*;

/**

* 目標(biāo)數(shù)據(jù)源注解,注解在方法上指定數(shù)據(jù)源的名稱(chēng)

*/

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

@Documented

public @interface TargetDataSource {

Stringvalue();//此處接收的是數(shù)據(jù)源的名稱(chēng)

}

6.創(chuàng)建DataSourceAspect

import lombok.extern.slf4j.Slf4j;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.aspectj.lang.reflect.MethodSignature;

import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**

* 數(shù)據(jù)源AOP切面定義

*/

@Component

@Aspect

@Slf4j

public class DataSourceAspect {

//切換放在mapper接口的方法上,所以這里要配置AOP切面的切入點(diǎn)

  @Pointcut("execution( * com.wondersgroup.yilian.largescreen_interface.dao.*.*(..))")

public void dataSourcePointCut() {

}

@Before("dataSourcePointCut()")

public void before(JoinPoint joinPoint) {

Object target = joinPoint.getTarget();

      String method = joinPoint.getSignature().getName();

      Class[] clazz = target.getClass().getInterfaces();

      Class[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();

      try {

Method m = clazz[0].getMethod(method, parameterTypes);

        //如果方法上存在切換數(shù)據(jù)源的注解,則根據(jù)注解內(nèi)容進(jìn)行數(shù)據(jù)源切換

        if (m !=null && m.isAnnotationPresent(TargetDataSource.class)) {

TargetDataSource data = m.getAnnotation(TargetDataSource.class);

            String dataSourceName = data.value();

            DynamicDataSourceHolder.putDataSource(dataSourceName);

            //log.debug("current thread " + Thread.currentThread().getName() + " add " + dataSourceName + " to ThreadLocal");

        }else {

//log.debug("switch datasource fail,use default");

        }

}catch (Exception e) {

//log.error("current thread " + Thread.currentThread().getName() + " add data to ThreadLocal error", e);

      }

}

//執(zhí)行完切面后,將線程共享中的數(shù)據(jù)源名稱(chēng)清空

  @After("dataSourcePointCut()")

public void after(JoinPoint joinPoint){

DynamicDataSourceHolder.removeDataSource();

  }

}

最后將自定義注解@TargetDataSource("dsa")根據(jù)不同的連接放在DAO層方法上。
(切記,如果在業(yè)務(wù)層加了事務(wù),數(shù)據(jù)源將無(wú)法切換)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容