Spring Boot系列:七、 实现Mybatis多数据源切换
一、引入相关maven配置
mybatis; mysql驱动;jdbc
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
二、编写配置文件
配置两个数据源:我这里配置了一个腾讯云的数据库和一个本地的数据库
分别指定四个字段:数据库链接、用户名、密码、驱动

三、编写数据库类型枚举
public enum DataSourceEnum {
TENCENT(0),LOCAL(1);
private int value;
private DataSourceEnum(int _value)
{
this.value=_value;
}
}
四、编写配置文件读取帮助类
注:我这里做这一步是为了更加透明的展示配置数据源的过程,如果想偷懒,这一一步可以不做,直接通过注解读取配置文件注入到容器中
DataSourceElement 数据库链接实体
/*数据库链接实体类
* 字段和配置文件保持一致*/
public class DataSourceElement { private String url; private String userName; private String password; private String classDirver;
//忽略getter setter
}
DataSourceItem 配置读取帮助类
@Component
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceItem {
//腾讯云链接 对应配置文件 tencent-db
private DataSourceElement tencentDb;
//本地链接 对应配置文件 local-db
private DataSourceElement localDb;
//忽略getter serrer
}
五、编写获取当前线程中执行的数据源的帮助类
这个类是为了指定我们当前线程中需要使用的数据源
public class DynamicDataSourceManger {
/*
* 初始化当前线程数据库类型*/
private static final ThreadLocal<DataSourceEnum> threadLocalDbType = new ThreadLocal<DataSourceEnum>() {
@Override
protected DataSourceEnum initialValue() {
return DataSourceEnum.TENCENT;
}
;
};
/*获取当前线程数据库*/
public static DataSourceEnum get() {
return threadLocalDbType.get();
}
/*设置当前线程数据库*/
public static void set(DataSourceEnum dataSourceEnum) {
threadLocalDbType.set(dataSourceEnum);
}
/*清楚当前线程数据库缓存*/
public static void reset() {
threadLocalDbType.remove();
}
}
六、继承AbstractRoutingDataSource
AbstractRoutingDataSource是spring提供的动态切换数据源工具类,他可以实现运行期间的数据源路由切换,具体内容请查看官方文档,我这里只写怎么用
简单的来说他会通过我们指定的key来获取我们设置的不同数据源,数据源的配置会在下面写到。
这里通过我们上面编写的DynamicDataSourceManger 拿到了当前线程需要执行的数据源的key
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
/*读取当前线程的数据源key值配置*/
return DynamicDataSourceManger.get();
}
}
七、配置多数据源以及AbstractRoutingDataSource的实现
注:下面的代码中我使用了通过我们在第四部编写的配置文件帮助类来获取配置文件的内容实现了Bean的注入,这么做是为了方便读者明白DataSource的创建过程
也可以直接使用 @ConfigurationProperties(prefix = "spring.datasource.tencent-db")直接装配上去,这样的话只需要写一行
DataSource dataSource = DataSourceBuilder.create().build();即可
注意事项:1.我们需要为不通的数据源指定不通的Bean名称,防止冲突
2.需要在获取AbstractRoutingDataSource实现的Bean上添加@Primary
3.编写完后需要关闭spring的自动配置数据源,否则会引发循环依赖(下面会写)
Spring容器注入类
/*数据源注入*/
@Configuration
public class DynamicDataSourceConfiguration { /*拿到数据库链接*/
@Autowired
DataSourceItem dataSourceItem; /*注入腾讯云数据库*/
@Bean(name = "TENCENTDB")
public DataSource getTencentDataSource() {
DataSourceElement tencentSoure = dataSourceItem.getTencentDb();
DataSource dataSource = DataSourceBuilder.create()
.url(tencentSoure.getUrl())
.username(tencentSoure.getUserName())
.password(tencentSoure.getPassword())
.driverClassName(tencentSoure.getClassDirver())
.build();
return dataSource;
} /*注入本地数据库*/
@Bean(name = "LOCALDB")
public DataSource getLocalDataSource() {
DataSourceElement localSource = dataSourceItem.getLocalDb();
DataSource dataSource = DataSourceBuilder.create()
.url(localSource.getUrl())
.username(localSource.getUserName())
.password(localSource.getPassword())
.driverClassName(localSource.getClassDirver())
.build();
return dataSource;
} /*注入AbstractRoutingDataSource*/
@Bean
@Primary
public DynamicDataSource getDyanmiceDataSource(@Qualifier("TENCENTDB") DataSource tencentDb,
@Qualifier("LOCALDB") DataSource localDb) { Map<Object,Object> hashMap=new HashMap<Object, Object>();
hashMap.put(DataSourceEnum.TENCENT,tencentDb);
hashMap.put(DataSourceEnum.LOCAL,localDb); DynamicDataSource dataSource=new DynamicDataSource();
/*设置数据源*/
dataSource.setTargetDataSources(hashMap);
/*设置默认数据源*/
dataSource.setDefaultTargetDataSource(tencentDb);
/*调用方法实现数据源配置*/
dataSource.afterPropertiesSet();
return dataSource;
} }
更改Spring Boot启动设置,关闭数据源自动注入和手动把我们的配置类注入到IOC容器中
@Import(DynamicDataSourceConfiguration.class)
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DynamicApplication { public static void main(String[] args) {
SpringApplication.run(DynamicApplication.class, args);
} }
八、编写实体类、Mybatis的Mapper和XML、配置Mybatis
这里我在腾讯云建了一个叫t_user的表,在本地库建了一个叫person的表
我们分别编写他们的Mapper和实体以及XML。
以下代码皆免去get和set,并且把代码都写在了一起方便对比,实际的时候是拆开写的(这是基础吧。。。。应该不用我说)
public class Person {
private Integer id;
private String name;
private String address;
private String province;
private String city;
private String area;
}
public class User {
private Integer id;
private String name;
private String sex;
private String address;
private String city;
private String area;
}
Mapper
@Mapper
public interface PersonMapper { List<Person> selectAllPerson();
} @Mapper
public interface UserMapper { List<User> selectAllUser();
}
XML
<mapper namespace="com.example.dynamic.mapper.PersonMapper">
<select id="selectAllPerson" resultType="com.example.dynamic.model.Person">
select * from person
</select>
</mapper> <mapper namespace="com.example.dynamic.mapper.UserMapper">
<select id="selectAllUser" resultType="com.example.dynamic.model.User">
select * from t_user
</select>
</mapper>
接口
我们在两个接口中,分别调用了腾讯云和本地两个数据源,在调用前通过在第五部编写的DynamicDataSourceManger来实现当前线程数据源key的切换
@RestController
@RequestMapping("/hello")
public class DynamicDataSourceController { @Autowired
UserMapper userMapper; @Autowired
PersonMapper personMapper; @RequestMapping("/user")
public List<User> selectAllUser(){
DynamicDataSourceManger.set(DataSourceEnum.TENCENT);
return userMapper.selectAllUser();
} @RequestMapping("/person")
public List<Person> selectAllPerson(){
DynamicDataSourceManger.set(DataSourceEnum.LOCAL);
return personMapper.selectAllPerson();
}
}
九、调用接口
调用腾讯云数据源

调用本地数据源

我们发现,这时候已经实现了多数据源的切换,这种写法其实有些生硬,需要手动设置数据源,可以通过AOP的方式把数据源设置编进去
十:编写Aspect实现动态切换
引入pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
自定义注解TargetDataSource,标明只能在函数上标注
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TargetDataSource { String value() default "";
}
自定义AOP切面类
@Component
@Aspect
public class DynamicSourceAspect { @Around("execution(* com.example.dynamic.mapper..*.*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("执行AOP");
//获取当前要执行的函数签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
//获取当前函数上的指定注解
TargetDataSource targetDataSource = method.getAnnotation(TargetDataSource.class);
//如果有指定注解的话设置为注解的值,没有的话设置默认腾讯云
if (targetDataSource == null) {
DynamicDataSourceManger.set(DataSourceEnum.TENCENT);
} else {
String dyType = targetDataSource.value();
switch (dyType) {
case "TENCENT":
DynamicDataSourceManger.set(DataSourceEnum.TENCENT);
break;
case "LOCAL":
DynamicDataSourceManger.set(DataSourceEnum.LOCAL);
break;
}
}
//执行函数
return joinPoint.proceed();
}
}
再次执行函数发现效果和上面是一样的。
Spring Boot系列:七、 实现Mybatis多数据源切换的更多相关文章
- Spring Boot (七)MyBatis代码自动生成和辅助插件
一.简介 1.1 MyBatis Generator介绍 MyBatis Generator 是MyBatis 官方出品的一款,用来自动生成MyBatis的 mapper.dao.entity 的框架 ...
- Spring Boot 系列总目录
一.Spring Boot 系列诞生原因 上学那会主要学的是 Java 和 .Net 两种语言,当时对于语言分类这事儿没什么概念,恰好在2009年毕业那会阴差阳错的先找到了 .Net 的工作,此后就开 ...
- Spring Boot (七): Mybatis极简配置
Spring Boot (七): Mybatis极简配置 1. 前言 ORM 框架的目的是简化编程中的数据库操作,经过这么多年的发展,基本上活到现在的就剩下两家了,一个是宣称可以不用写 SQL 的 H ...
- Spring Boot系列(三):Spring Boot整合Mybatis源码解析
一.Mybatis回顾 1.MyBatis介绍 Mybatis是一个半ORM框架,它使用简单的 XML 或注解用于配置和原始映射,将接口和Java的POJOs(普通的Java 对象)映射成数据库中的记 ...
- 国内最全的Spring Boot系列之二
历史文章 <国内最全的Spring Boot系列之一> 视频&交流平台 SpringBoot视频:http://t.cn/R3QepWG Spring Cloud视频:http:/ ...
- 07.深入浅出 Spring Boot - 数据访问之Mybatis(附代码下载)
MyBatis 在Spring Boot应用非常广,非常强大的一个半自动的ORM框架. 代码下载:https://github.com/Jackson0714/study-spring-boot.gi ...
- spring boot系列01--快速构建spring boot项目
最近的项目用spring boot 框架 借此学习了一下 这里做一下总结记录 非常便利的一个框架 它的优缺点我就不在这背书了 想了解的可以自行度娘谷歌 说一下要写什么吧 其实还真不是很清楚,只是想记录 ...
- Spring Boot系列(四):Spring Boot源码解析
一.自动装配原理 之前博文已经讲过,@SpringBootApplication继承了@EnableAutoConfiguration,该注解导入了AutoConfigurationImport Se ...
- spring mvc+mybatis+多数据源切换
spring mvc+mybatis+多数据源切换,选取oracle,mysql作为例子切换数据源.oracle为默认数据源,在测试的action中,进行mysql和oracle的动态切换. web. ...
- spring+mybatis多数据源切换
在实际的公司项目中,很可能会遇到一个问题就是,一个java项目,但是项目中涉及两个数据库,这两个数据库还在不同IP的机子上. 遇到这种情况的时候,我们有两个选择 1.不走spring的aop方式,直接 ...
随机推荐
- .netcore使用autofac
.netcore3.1使用autofac (.netcore中本身已经实现了IOC容器,其实没有必要替换成autofac.如果非常习惯autofac,替换也是无可厚非的.) 第一步.在项目中引入Aut ...
- ATcoder Grand Contest总结
最前面: AT的题都很有思维难度,总结一下一些AT的常规操作 1.对于有操作的题目,如果正面推不行的话考虑倒推,将操作转化,寻找更好的性质 2.模型转化,看到某一种的计算的式子,需要考虑有没有更简化的 ...
- Oracle数据库系统结构(一)
1.Oracle数据库系统结构概述 Oracle数据库由存放在磁盘上的数据库(DB)和对磁盘上的数据库进行管理的数据库管理系统(DBMS)两部分构成,分别对应着数据库的存储结构和软件结构. Oracl ...
- Facebook 的神仙组长什么样?
这里是<齐姐聊大厂>系列的第 14 篇 每周五早上 8 点,与你唠唠大厂的那些事 号外号外!前 12 篇已出 PDF:公粽号后台回复「大厂」即可获得! ❝ 小齐说: 这篇文章是来自阿米粥的 ...
- c++中的几种函数调用约定(转)
C++中的函数调用约定(调用惯例)主要针对三个问题: 1.参数传递的方式(是否采用寄存器传递参数.采用哪个寄存器传递参数.参数压桟的顺序等): 参数的传递方式,最常见的是通过栈传递.函数的调用方将参数 ...
- 自定义圆角背景的textview,抛弃shape
自定义一个圆角背景的TextView,解放双手,不用再写shape了. 1.values目录新建attrs.xml. <?xml version="1.0" encoding ...
- ssh配好无密码登录(RSA公钥)后,还要密码登录的问题的解决办法
首先删除 /root/.ssh目录 然后ssh-keygen 生成新的认证目录 然后检查能否免密码登陆 如果还不能可能是/root/目录的权限不对了 可能被异常改到777了 做操作 chmod 650 ...
- EF Core 二 、 入门 EF Core
入门EF Core 我们将开始真正的EF之旅了,这里使用SqlServer数据,然后DbFirst: 为嘛使用SqlServer,目前公司的整体业务全部在SqlSever,所以很多产品业务都是依托于这 ...
- RESTFul服务开发必备的一款IDEA插件!用了就离不开了
我们经常谈 RESTful Web 服务开发,但是我发现很多人实际就根本不懂这个概念.只是听着大家都这么说,也就跟着一起说了,哈哈哈! 因此,在开始推荐这个IDEA插件之前,非常有必要花一小会时间简单 ...
- Apache POI读写Excel
Apache POI是Apache软件基金会的开放源码函式库,POIAPI给Java程序对Microsoft Office格式档案读和写的功能. 官方文档 [https://poi.apache.or ...