前言

  在实际项目中,我们可能会碰到在一个项目中会访问多个数据库的情况。针对这种情况,我们就需要配置动态的数据源了。一般按照以下步骤即可

一、在启动类上添加注解

二、在application.properties文件中

#默认数据源

spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://127.0.0.1:3306/tianxi_mall?useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8&allowMultiQueries=true

spring.datasource.username = root
spring.datasource.password =

#其他数据源.sqlserver
custom.datasource.names = ds1
custom.datasource.ds1.driver-class-name = com.mysql.jdbc.Driver
custom.datasource.ds1.url = jdbc:mysql://192.168.2.2:3306/wechat?useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8&allowMultiQueries=true
custom.datasource.ds1.username = root
custom.datasource.ds1.password =

注:假如其他的数据源不是mysql,请自行百度其他数据的连接驱动

三、配置

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

/**
* AbstractRoutingDataSource获取数据源之前会先调用determineCurrentLookupKey方法查找当前的lookupKey,这个lookupKey就是数据源标识。
因此通过重写这个查找数据源标识的方法就可以让spring切换到指定的数据源了
* @author mayn
*
*/
public class DynamicDataSource extends AbstractRoutingDataSource{
protected Object determineCurrentLookupKey() {
//从自定义位置获取数据源标识
return DynamicDataSourceContextHolder.getDataSourceType();
}
}

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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* // 保证该AOP在@Transactional之前执行
* @author mayn
*
*/
@Component
@Aspect
@Order(-1)
public class DynamicDataSourceAspect {
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);

@Before("@annotation(ds)")
public void changeDataSource(JoinPoint point, TargetDataSource ds) throws Throwable {
String dsId = ds.name();
if (!DynamicDataSourceContextHolder.containsDataSource(dsId)) {
logger.error("数据源[{}]不存在,使用默认数据源 > {}", ds.name(), point.getSignature());
} else {
logger.debug("Use DataSource : {} > {}", ds.name(), point.getSignature());
DynamicDataSourceContextHolder.setDataSourceType(ds.name());
}
}

@After("@annotation(ds)")
public void restoreDataSource(JoinPoint point, TargetDataSource ds) {
logger.debug("Revert DataSource : {} > {}", ds.name(), point.getSignature());
DynamicDataSourceContextHolder.clearDataSourceType();
}
}

import java.util.ArrayList;
import java.util.List;

/**
* 用于持有当前线程中使用的数据源标识
* @author mayn
*
*/
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static List<String> dataSourceIds = new ArrayList<>();

public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}

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

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

/** * 判断指定DataSrouce当前是否存在 * */
public static boolean containsDataSource(String dataSourceId){
return dataSourceIds.contains(dataSourceId);
}
}

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);

private ConversionService conversionService = new DefaultConversionService();
private PropertyValues dataSourcePropertyValues;

// 如配置文件中未指定数据源类型,使用该默认值
private static final Object DATASOURCE_TYPE_DEFAULT = "org.apache.tomcat.jdbc.pool.DataSource";
// private static final Object DATASOURCE_TYPE_DEFAULT =
// "com.zaxxer.hikari.HikariDataSource";

// 数据源
private DataSource defaultDataSource;
private Map<String, DataSource> customDataSources = new HashMap<>();

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
// 将主数据源添加到更多数据源中
targetDataSources.put("dataSource", defaultDataSource);
DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
// 添加更多数据源
targetDataSources.putAll(customDataSources);
for (String key : customDataSources.keySet()) {
DynamicDataSourceContextHolder.dataSourceIds.add(key);
}

// 创建DynamicDataSource
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(DynamicDataSource.class);
beanDefinition.setSynthetic(true);
MutablePropertyValues mpv = beanDefinition.getPropertyValues();
mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
mpv.addPropertyValue("targetDataSources", targetDataSources);
registry.registerBeanDefinition("dataSource", beanDefinition);

logger.info("Dynamic DataSource Registry");
}

/** * 创建DataSource * * @param type * @param driverClassName * @param url * @param username * @param password * @return * @author SHANHY * @create 2016年1月24日 */
@SuppressWarnings("unchecked")
public DataSource buildDataSource(Map<String, Object> dsMap) {
try {
Object type = dsMap.get("type");
if (type == null)
type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource

Class<? extends DataSource> dataSourceType;
dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);

String driverClassName = dsMap.get("driver-class-name").toString();
String url = dsMap.get("url").toString();
String username = dsMap.get("username").toString();
String password = dsMap.get("password").toString();

DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
.username(username).password(password).type(dataSourceType);
return factory.build();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}

/** * 加载多数据源配置 */
public void setEnvironment(Environment env) {
initDefaultDataSource(env);
initCustomDataSources(env);
}

/** * 初始化主数据源 * * @author SHANHY * @create 2016年1月24日 */
private void initDefaultDataSource(Environment env) {
// 读取主数据源
RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "spring.datasource.");
Map<String, Object> dsMap = new HashMap<>();
dsMap.put("type", propertyResolver.getProperty("type"));
dsMap.put("driver-class-name", propertyResolver.getProperty("driver-class-name"));
dsMap.put("url", propertyResolver.getProperty("url"));
dsMap.put("username", propertyResolver.getProperty("username"));
dsMap.put("password", propertyResolver.getProperty("password"));

defaultDataSource = buildDataSource(dsMap);

dataBinder(defaultDataSource, env);
}

/** * 为DataSource绑定更多数据 * * @param dataSource * @param env * @author SHANHY * @create 2016年1月25日 */
private void dataBinder(DataSource dataSource, Environment env){
RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
//dataBinder.setValidator(new LocalValidatorFactory().run(this.applicationContext));
dataBinder.setConversionService(conversionService);
dataBinder.setIgnoreNestedProperties(false);//false
dataBinder.setIgnoreInvalidFields(false);//false
dataBinder.setIgnoreUnknownFields(true);//true
if(dataSourcePropertyValues == null){
Map<String, Object> rpr = new RelaxedPropertyResolver(env, "spring.datasource").getSubProperties(".");
Map<String, Object> values = new HashMap<>(rpr);
// 排除已经设置的属性
values.remove("type");
values.remove("driver-class-name");
values.remove("url");
values.remove("username");
values.remove("password");
dataSourcePropertyValues = new MutablePropertyValues(values);
}
dataBinder.bind(dataSourcePropertyValues);
}

/** * 初始化更多数据源 * * @author SHANHY * @create 2016年1月24日 */
private void initCustomDataSources(Environment env) {
// 读取配置文件获取更多数据源,也可以通过defaultDataSource读取数据库获取更多数据源
RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "custom.datasource.");
String dsPrefixs = propertyResolver.getProperty("names");
for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源
Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");
DataSource ds = buildDataSource(dsMap);
customDataSources.put(dsPrefix, ds);
dataBinder(ds, env);
}
}
}

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 自定义注解
* @author mayn
*
*/
@Target({ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
String name();
}

四、配置完成后,只需在要切换数据源的映射接口上添加注解@TargetDataSource(name="ds1") 即可。注意,ds1是自定义的,对应了配置application.properties中的ds1,如下

/**
* 切换数据源查询
*/
@TargetDataSource(name="ds1")
public List<CardInfoResponse> cardInfo(String card_id) {
return cardMapper.cardInfo(card_id);
}

五、至此,完成,亲测有效。假如需要拓展更多的数据源,则相应继续往下配置即可。

Springbooot +Mybaties 配置数据库多数据源的更多相关文章

  1. 如何配置数据库ODBC数据源

    在<调整计算机的设置>中,点击<系统和安全>.   点击<管理工具>.   点击<数据源(ODBC)>.   点击<系统用户>,然后,点击按 ...

  2. Spring主从数据库的配置和动态数据源切换原理

    原文:https://www.liaoxuefeng.com/article/00151054582348974482c20f7d8431ead5bc32b30354705000 在大型应用程序中,配 ...

  3. 配置ODBC DSN数据源,导出数据库数据到Excel过程记录

    一.前言 工作中我们可能遇到这样的需要:查询数据库中的信息,并将结果导出到Excel文件.这本来没什么,但数据量比较大时,用PLSQL.toad导出Excel会出现内存不足等情况,使用odbc+Mic ...

  4. Spring配置多个数据源

    Spring 配置多数据源实现数据库读写分离 博客分类: Spring 数据库   现在大型的电子商务系统,在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库.Mast ...

  5. tomcat配置JNDI获取数据源

    各个web工程可以通过工程内的xml文件配置访问数据库的数据源,这样的配置是各个工程私有的.基于JNDI为tomcat配置数据源,则可以做成全局的,各工程只需要通过便签引用数据源即可. 1.需要将数据 ...

  6. SpringMVC+Mybatis 如何配置多个数据源并切换?

    最近公司一个项目需要连接两个数据库(A和B)操作,有的模块查询A库,有的模块查询B库,因此需要改造下,项目后台用的是SpringMVC+Mybatis+MySQL架构,折腾了两天后终于搞定了,在这里记 ...

  7. SpringBoot入门之基于Druid配置Mybatis多数据源

    上一篇了解了Druid进行配置连接池的监控和慢sql处理,这篇了解下使用基于基于Druid配置Mybatis多数据源.SpringBoot默认配置数据库连接信息时只需设置url等属性信息就可以了,Sp ...

  8. 20. Spring Boot 默认、自定义数据源 、配置多个数据源 jdbcTemplate操作DB

    Spring-Boot-2.0.0-M1版本将默认的数据库连接池从tomcat jdbc pool改为了hikari,这里主要研究下hikari的默认配置 0.  创建Spring Boot项目,选中 ...

  9. 配置多个数据源,spring profile 多环境配置管理

    针对生产环境,测试环境,以及本地调试开发有时会配置多套数据库,在一个数据配置文件进行修改,往往有时发布到生成环境会忘记修改,或者本地调试时还是生产环境的库,会导致生产环境数据被污染. ps--刚开始配 ...

随机推荐

  1. docker同步时区时间

    在Docker容器创建好之后,可能会发现容器时间跟宿主机时间不一致,这就需要同步它们的时间,让容器时间跟宿主机时间保持一致.如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 ...

  2. Xcode $(SRCROOT)和$(PROJECT_DIR)区别

    $(SRCROOT)代表的时项目根目录下 $(PROJECT_DIR)代表的是整个项目 PS:往项目添加文件时,例如.a等,要先show in finder ,复制到项目中,然后再拖到xcode项目中 ...

  3. Windows Server 2008 安装 10.2.0.5 单实例

    需求:Windows Server 2008 安装 10.2.0.5 单实例 原以为非常简单的一次任务,实际却遇到了问题,故记录一下. 1.安装10.2.0.1 2.安装10.2.0.4 3.安装10 ...

  4. SQLServer 里面的 DDL,DML,DCL,TCL(转)

    1.DDL (Data Definition Language )数据库定义语言 statements are used to define the database structure or sch ...

  5. webpack使用六

    插件(Plugins) 插件(Plugins)是用来拓展Webpack功能的,它们会在整个构建过程中生效,执行相关的任务. Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西,可以 ...

  6. Codeforces Round #402 D String Game(二分)

    [题目类型]二分答案 &题解: 只要你想到二分答案就不是难题了,但我当时确实是想不到. [时间复杂度]\(O(nlogn)\) &代码: #include <cstdio> ...

  7. composer----------composer基本命令和遇到一些问题解决方案

    1.composer跟xdebug有冲突,每次用composer命令的时候都要报xdebug的错误,去php的配置文件里面将xdebug注释掉就可以了,但是我注释掉了以后还是不行.找了半天才看到,我用 ...

  8. MyBatis基础入门《十四》ResultMap子元素(association )

    MyBatis基础入门<十四>ResultMap子元素(association ) 1. id: >> 一般对应数据库中改行的主键ID,设置此项可以提高Mybatis的性能 2 ...

  9. 不同版本Hibernate.获取SessionFactory的方式

    不同版本Hibernate.获取SessionFactory的方式 Hibernate 版本说明: 我当前使用的是 Hibernate 5.x ,(hibernate-release-5.3.6.Fi ...

  10. c# 集合中有数字、字符的Orderby排序

    string[] things= new string[] { "105", "101", "102", "103", ...