文章转自 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 Future用法和意义一句话击破

    在并发编程时,一般使用runnable,然后扔给线程池完事,这种情况下不需要线程的结果. 所以run的返回值是void类型. 如果是一个多线程协作程序,比如菲波拉切数列,1,1,2,3,5,8...使 ...

  2. 数据库编程Case when

    数据库编程题 1. 姓名 日期 是否上班 张三 星期二 是 张三 星期三 是 李四 星期一 是 王五 星期二 是 张三 星期二 是 写出一条SQL语句输出下列结果 姓名 星期一 星期二 星期三 张三 ...

  3. C#特性之数据类型

    这篇文章主要通过演示类在不同发展中的不通过定义方法,来向读者表述它们之间的区别和联系. 在C#1时代,我们喜欢这样定义类: public class Product { private string ...

  4. 关于IOS下click事件委托失效的解决方案

    一.由于某些特殊情况下,需要用到事件委托,比如给动态创建的DOM绑定click事件,这里就需要事件委托(这里就牵扯到:目标元素和代理元素)目标元素:动态创建的元素,最终click事件需要绑定到该元素 ...

  5. 使用git连接本地和远程github

    使用git连接本地和远程github 网上很多github的流程比较乱,自己尝试整理了一下,主要是步骤较为清晰,如果有不清楚的可详细进行搜索对比 1. 申请和设置github https://gith ...

  6. [js高手之路]深入浅出webpack教程系列2-配置文件webpack.config.js详解(上)

    [js高手之路]深入浅出webpack教程系列索引目录: [js高手之路]深入浅出webpack教程系列1-安装与基本打包用法和命令参数 [js高手之路]深入浅出webpack教程系列2-配置文件we ...

  7. 【读书笔记】iOS-发布你的应用

    一,添加图标 你的应用在iPhone主屏幕上的标准图标(Icon.png)是57像素*57像素的正方形,PNG格式,不能有透明效果或者图层,72DPI.除些之外,你还可以提供一个同样格式的114像素* ...

  8. vue-cli脚手架之webpack.prod.conf.js

    webpack.prod.conf.js 生产环境配置文件: 'use strict'//js严格模式执行 const path = require('path')//这个模块是发布到NPM注册中心的 ...

  9. Ubuntu中针对问题 E: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)的解决方案

    一.问题描述: 在ubuntu中有时因为错误的操作,而导致在执行 sudo apt-get install xxxx出现如下错误: E: Could not get lock /var/lib/dpk ...

  10. Android View 绘制流程

    Android 中 Activity 是作为应用程序的载体存在,代表着一个完整的用户界面,提供了一个窗口来绘制各种视图,当 Activity 启动时,我们会通过 setContentView 方法来设 ...