文章转自 https://blog.csdn.net/neosmith/article/details/61202084

网上的文章基本上都是只有多数据源或只有动态数据源,而最近的项目需要同时使用两种方式,记录一下配置方法供大家参考。

应用场景

项目需要同时连接两个不同的数据库A, B,并且它们都为主从架构,一台写库,多台读库。

多数据源

首先要将spring boot自带的DataSourceAutoConfiguration禁掉,因为它会读取application.properties文件的spring.datasource.*属性并自动配置单数据源。在@SpringBootApplication注解中添加exclude属性即可:

@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class
})
public class TitanWebApplication {
public static void main(String[] args) {
SpringApplication.run(TitanWebApplication.class, args);
}
}

然后在application.properties中配置多数据源连接信息:

# titan库
spring.datasource.titan-master.url=jdbc:mysql://X.X.X.X:port/titan?characterEncoding=UTF-8
spring.datasource.titan-master.username=
spring.datasource.titan-master.password=
spring.datasource.titan-master.driver-class-name=com.mysql.jdbc.Driver
# 连接池配置
# 省略 # 其它库
spring.datasource.db2.url=jdbc:mysql://X.X.X.X:port/titan2?characterEncoding=UTF-8
spring.datasource.db2.username=
spring.datasource.db2.password=
spring.datasource.db2.driver-class-name=com.mysql.jdbc.Driver

由于我们禁掉了自动数据源配置,因些下一步就需要手动将这些数据源创建出来:

@Configuration
public class DataSourceConfig { @Bean(name = "titanMasterDS")
@ConfigurationProperties(prefix = "spring.datasource.titan-master") // application.properteis中对应属性的前缀
public DataSource dataSource1() {
return DataSourceBuilder.create().build();
} @Bean(name = "ds2")
@ConfigurationProperties(prefix = "spring.datasource.db2") // application.properteis中对应属性的前缀
public DataSource dataSource2() {
return DataSourceBuilder.create().build();
} }

接下来需要配置两个mybatis的SqlSessionFactory分别使用不同的数据源:

@Configuration
@MapperScan(basePackages = {"titan.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory1")
public class MybatisDbAConfig { @Autowired
@Qualifier("titanMasterDS")
private DataSource ds1; @Bean
public SqlSessionFactory sqlSessionFactory1() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(ds1); // 使用titan数据源, 连接titan库 return factoryBean.getObject(); } @Bean
public SqlSessionTemplate sqlSessionTemplate1() throws Exception {
SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory1()); // 使用上面配置的Factory
return template;
}
}

经过上面的配置后,titan.mapper下的Mapper接口,都会使用titan数据源。同理可配第二个SqlSessionFactory:

@Configuration
@MapperScan(basePackages = {"other.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory2")
public class MybatisDbBConfig {
@Autowired
@Qualifier("ds2")
private DataSource ds2; @Bean
public SqlSessionFactory sqlSessionFactory2() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(ds2); return factoryBean.getObject(); } @Bean
public SqlSessionTemplate sqlSessionTemplate2() throws Exception {
SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory2());
return template;
}
}

完成这些配置后,假设有2个Mapper titan.mapper.UserMapperother.mapper.RoleMapper,使用前者时会自动连接titan库,后者连接ds2库。

动态数据源

使用动态数据源的初衷,是能在应用层做到读写分离,即在程序代码中控制不同的查询方法去连接不同的库。除了这种方法以外,数据库中间件也是个不错的选择,它的优点是数据库集群对应用来说只暴露为单库,不需要切换数据源的代码逻辑。

我们通过自定义注解 + AOP的方式实现数据源动态切换。

首先定义一个ContextHolder, 用于保存当前线程使用的数据源名:

public class DataSourceContextHolder {
public static final Logger log = LoggerFactory.getLogger(DataSourceContextHolder.class); /**
* 默认数据源
*/
public static final String DEFAULT_DS = "titan-master"; private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); // 设置数据源名
public static void setDB(String dbType) {
log.debug("切换到{}数据源", dbType);
contextHolder.set(dbType);
} // 获取数据源名
public static String getDB() {
return (contextHolder.get());
} // 清除数据源名
public static void clearDB() {
contextHolder.remove();
}
}

然后自定义一个javax.sql.DataSource接口的实现,这里只需要继承Spring为我们预先实现好的父类AbstractRoutingDataSource即可:

public class DynamicDataSource extends AbstractRoutingDataSource {
private static final Logger log = LoggerFactory.getLogger(DynamicDataSource.class); @Override
protected Object determineCurrentLookupKey() {
log.debug("数据源为{}", DataSourceContextHolder.getDB()); return DataSourceContextHolder.getDB();
} }

创建动态数据源:

/**
* 动态数据源: 通过AOP在不同数据源之间动态切换
* @return
*/
@Bean(name = "dynamicDS1")
public DataSource dataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(dataSource1()); // 配置多数据源
Map<Object, Object> dsMap = new HashMap(5);
dsMap.put("titan-master", dataSource1());
dsMap.put("ds2", dataSource2()); dynamicDataSource.setTargetDataSources(dsMap); return dynamicDataSource;
}

自定义注释@DS用于在编码时指定方法使用哪个数据源:

@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.METHOD
})
public @interface DS {
String value() default "titan-master";
}

切面,实现切换逻辑:

@Aspect
@Component
public class DynamicDataSourceAspect { @Before("@annotation(DS)")
public void beforeSwitchDS(JoinPoint point){ //获得当前访问的class
Class<?> className = point.getTarget().getClass(); //获得访问的方法名
String methodName = point.getSignature().getName();
//得到方法的参数的类型
Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
String dataSource = DataSourceContextHolder.DEFAULT_DS;
try {
// 得到访问的方法对象
Method method = className.getMethod(methodName, argClass); // 判断是否存在@DS注解
if (method.isAnnotationPresent(DS.class)) {
DS annotation = method.getAnnotation(DS.class);
// 取出注解中的数据源名
dataSource = annotation.value();
}
} catch (Exception e) {
e.printStackTrace();
} // 切换数据源
DataSourceContextHolder.setDB(dataSource); } @After("@annotation(DS)")
public void afterSwitchDS(JoinPoint point){ DataSourceContextHolder.clearDB(); }
}

完成上述配置后,在先前SqlSessionFactory配置中指定使用DynamicDataSource就可以在Service中愉快的切换数据源了:

@Autowired
private UserAModelMapper userAMapper; @DS("titan-master")
public String ds1() {
return userAMapper.selectByPrimaryKey(1).getName();
} @DS("ds2")
public String ds2() {
return userAMapper.selectByPrimaryKey(1).getName();
}

Spring Boot + Mybatis多数据源和动态数据源配置的更多相关文章

  1. Spring Boot数据访问之动态数据源切换之使用注解式AOP优化

    在Spring Boot数据访问之多数据源配置及数据源动态切换 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中详述了如何配置多数据源及多数据源之间的动态切换.但是需要读数据库的地方,就 ...

  2. Spring Boot 2.x Redis多数据源配置(jedis,lettuce)

    Spring Boot 2.x Redis多数据源配置(jedis,lettuce) 96 不敢预言的预言家 0.1 2018.11.13 14:22* 字数 65 阅读 727评论 0喜欢 2 多数 ...

  3. Spring Boot数据访问之多数据源配置及数据源动态切换

    如果一个数据库数据量过大,考虑到分库分表和读写分离需要动态的切换到相应的数据库进行相关操作,这样就会有多个数据源.对于一个数据源的配置在Spring Boot数据访问之数据源自动配置 - 池塘里洗澡的 ...

  4. spring boot mybatis XML文件读取properties配置信息

    配置文件application.properties中相关配置信息可以在部署以后修改,引用配置信息可以在代码和mybatis的映射文件中 1.JAVA代码 可以通过变量去读取 application. ...

  5. 分布式事务、多数据源、分库分表中间件之spring boot基于Atomikos+XADataSource分布式事务配置(100%纯动态)

    本文描述spring boot基于Atomikos+DruidXADataSource分布式事务配置(100%纯动态),也就是增加.减少数据源只需要修改application.properties文件 ...

  6. Spring Boot + Mybatis 实现动态数据源

    动态数据源 在很多具体应用场景的时候,我们需要用到动态数据源的情况,比如多租户的场景,系统登录时需要根据用户信息切换到用户对应的数据库.又比如业务A要访问A数据库,业务B要访问B数据库等,都可以使用动 ...

  7. Spring Boot 入门系列(二十三)整合Mybatis,实现多数据源配置!

    d之前介绍了Spring Boot 整合mybatis 使用注解方式配置的方式实现增删改查以及一些复杂自定义的sql 语句 .想必大家对spring boot 项目中,如何使用mybatis 有了一定 ...

  8. Spring Boot + MyBatis + Pagehelper 配置多数据源

    前言: 本文为springboot结合mybatis配置多数据源,在项目当中很多情况是使用主从数据源来读写分离,还有就是操作多库,本文介绍如何一个项目同时使用2个数据源. 也希望大家带着思考去学习!博 ...

  9. Spring Boot + Mybatis 配置多数据源

    Spring Boot + Mybatis 配置多数据源 Mybatis拦截器,字段名大写转小写 package com.sgcc.tysj.s.common.mybatis; import java ...

随机推荐

  1. Java中的集合迭代器

    集合的迭代器 任何集合都有迭代器. 任何集合类,都必须能以某种方式存取元素,否则这个集合容器就没有任何意义. 迭代器,也是一种模式(也叫迭代器模式).在java中它是一个对象,其目的是遍历并选中其中的 ...

  2. [PHP] 算法-数组重复数字统计的PHP实现

    在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为7的数组{ ...

  3. Spring全家桶系列–SpringBoot之AOP详解

    //本文作者:cuifuan //本文将收录到菜单栏:<Spring全家桶>专栏中 面向方面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP). OOP中模块化的关 ...

  4. ionic 项目中ios上遇到的软键盘输入法自动弹出的问题

    一.  安装插件 cordova plugin add ionic-plugin-keyboard 二. 软键盘显示监听 window.addEventListener('native.keyboar ...

  5. 常见编码GBK、GB2312、UTF-8、ISO-8859-1的区别

    https://blog.csdn.net/shijing_0214/article/details/50908144 在项目开发中,会经常遇到不同的编码方式.不管什么编码,都是信息在计算机中的一种表 ...

  6. MIPS 安全相关paper阅读笔记

    前言 论文来自 ​ https://cyber-itl.org/2018/12/07/a-look-at-home-routers-and-linux-mips.html Linux_MIPS_mis ...

  7. JQuery请求数据的方式

    /*$.ajax常用的几个参数 // 1.url:要求为String类型的参数,(默认为当前页地址)发送请求的地址. // 2.type:要求为String类型的参数,请求方式(post或get)默认 ...

  8. 【Java入门提高篇】Day32 Java容器类详解(十四)ArrayDeque详解

    今天来介绍一个不太常见也不太常用的类——ArrayDeque,这是一个很不错的容器类,如果对它还不了解的话,那么就好好看看这篇文章吧. 看完本篇,你将会了解到: 1.ArrayDeque是什么? 2. ...

  9. JavaScript大杂烩9 - 理解BOM

    毫无疑问,我们学习JavaScript是为了完成特定的功能.在最初的JavaScript类型系统中,我们已经分析过JavaScript在页面开发中充当着添加逻辑的角色,而且我们知道JavaScript ...

  10. [20170623]利用传输表空间恢复部分数据.txt

    [20170623]利用传输表空间恢复部分数据.txt --//昨天我测试使用传输表空间+dblink,上午补充测试发现表空间设置只读才能执行impdp导入原数据,这个也很好理解.--//这样的操作模 ...