SpringBoot2 + Druid + Mybatis 多数据源动态配置
在大数据高并发的应用场景下,为了更快的响应用户请求,读写分离是比较常见的应对方案。读写分离会使用多数据源的使用。下面记录如何搭建SpringBoot2 + Druid + Mybatis 多数据源配置以及在使用过程遇到的问题。
一、先从pom.xml入手(使用springboot 2的版本)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
</dependencies>
inject是java依赖注入标准。spring默认支持识别。spring自带的@Autowired的缺省情况等价于JSR-330的@Inject注解;@Qualifier的缺省的根据Bean名字注入情况等价于JSR-330的@Named注解。
二、添加读取DB的Mapper
@Mapper
public interface AssetMapper { @Select("select * from Asset where account = #{account}")
Asset queryName(String account);
}
此处使用mybatis的注解功能,因此可以少省去*.xml等配置文件。
三、添加多数据源的配置参数
spring.datasource.druid.write.url=jdbc:mysql://192.168.0.110:3306/master?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.druid.write.username=root
spring.datasource.druid.write.password=123456
spring.datasource.druid.write.driver-class-name=com.mysql.cj.jdbc.Driver
#
spring.datasource.druid.read.url=jdbc:mysql://192.168.0.110:3306/slave1?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.druid.read.username=root
spring.datasource.druid.read.password=123456
spring.datasource.druid.read.driver-class-name=com.mysql.cj.jdbc.Driver 新版本mysql的url后面必需要添加serverTimezone=。 不然会报以下异常:
2019-06-05 18:47:24.058 ERROR 17804 --- [-Create-6910184] com.alibaba.druid.pool.DruidDataSource : create connection SQLException, url: jdbc:mysql://localhost:3306/master, errorCode 0, state 01S00 java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
四、配置数据源
@Configuration
public class DataSourceConfig { @Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.write")
@Primary
public DataSource masterDataSource() {
return DruidDataSourceBuilder.create().build();
} @Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.read")
public DataSource slaveDataSource() {
return DruidDataSourceBuilder.create().build();
} @Inject
@Named("masterDataSource")
private DataSource masterDataSource; @Inject
@Named("slaveDataSource")
private DataSource slaveDataSource; /**
* 根据数据源创建SqlSessionFactory
*/
@Bean
public SqlSessionFactory sqlSessionFactory(DynamicDataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
return sessionFactory.getObject();
}
}
SqlSessionFactory必需要重新创建,若不创建会报循环调用异常
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'masterDataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?
因为SqlSessionFactory还是走默认创建的方式 。
上下文中如何得知使用那个数据源,可使用ThreadLocal来处理。
五、数据源路由
public class DataSourceContextRouting implements AutoCloseable {
static final ThreadLocal<String> dataSourceKeyThreadLocal = new ThreadLocal<>();
public String getDataSourceName(){
String key = dataSourceKeyThreadLocal.get();
return StringUtils.isBlank(key) ?"masterDataSource":key;
}
public DataSourceContextRouting(String key){
dataSourceKeyThreadLocal.set(key);
}
@Override
public void close() throws Exception {
dataSourceKeyThreadLocal.remove();
}
}
spring的提供动态源实现功能。只需要继承AbstractRoutingDataSource,并重写protected Object determineCurrentLookupKey()
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextRouting.getDataSourceName();
}
}
//此为核心代码
@Bean
public DynamicDataSource dataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("masterDataSource", masterDataSource);
targetDataSources.put("slaveDataSource", slaveDataSource);
DynamicDataSource dataSource = new DynamicDataSource();
//设置数据源映射
dataSource.setTargetDataSources(targetDataSources);
//设置默认数据源,当无法映射到数据源时会使用默认数据源
dataSource.setDefaultTargetDataSource(slaveDataSource);
dataSource.afterPropertiesSet();
return dataSource;
}
六、controller路由切换
@RequestMapping("master")
public String master(String account){
String key = "masterDataSource";
new DataSourceContextRouting(key);
//TODO .....
}
@RequestMapping("slave")
public String slave(String account){
String key = "slaveDataSource";
new DataSourceContextRouting(key);
//TODO......
}
到此为止,整个多数据源配置完成了。
但这种对代码侵入比较多,可以使用注解的方式来处理。先定义注解标识
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
String value();
}
使用注解那需要对此进行解析切入,因此就需要用上spring AOP的功能。
首先添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
然后添加对其解析Aspect
@Aspect
@Named
public class DataSourceRoutingAspect {
@Around("@annotation(targetDataSource)")
public Object routingWithDataSource(ProceedingJoinPoint joinPoint, TargetDataSource targetDataSource) throws Throwable {
String key = targetDataSource.value();
try (DataSourceContextRouting ctx = new DataSourceContextRouting(key)) {
return joinPoint.proceed();
}
}
}
@RequestMapping("master")
@TargetDataSource("masterDataSource")
public String master(String account){
TODO:.....
}
@RequestMapping("slave")
@TargetDataSource("slaveDataSource")
public String slave(String account){
TODO:.....
}
SpringBoot2 + Druid + Mybatis 多数据源动态配置的更多相关文章
- Springboot+Mybatis+Pagehelper+Aop动态配置Oracle、Mysql数据源
本文链接:https://blog.csdn.net/wjy511295494/article/details/78825890 Springboot+Mybatis+Pagehelper+Aop ...
- springboot2.0+mybatis多数据源集成
最近在学springboot,把学的记录下来.主要有springboot2.0+mybatis多数据源集成,logback日志集成,springboot单元测试. 一.代码结构如下 二.pom.xml ...
- springboot2.1+redis多数据源的配置
springboot系列学习笔记全部文章请移步值博主专栏**: spring boot 2.X/spring cloud Greenwich. 由于是一系列文章,所以后面的文章可能会使用到前面文 ...
- spring-boot 速成(9) druid+mybatis 多数据源及读写分离的处理
按上节继续学习,稍微复杂的业务系统,一般会将数据库按业务拆开,比如产品系统的数据库放在product db中,订单系统的数据库放在order db中...,然后,如果量大了,可能每个库还要考虑做读.写 ...
- spring+mybatis多数据源动态切换
spring mvc+mybatis+多数据源切换 选取oracle,mysql作为例子切换数据源.oracle为默认数据源,在测试的action中,进行mysql和oracle的动态切换. web. ...
- Spring, MyBatis 多数据源的配置和管理
同一个项目有时会涉及到多个数据库,也就是多数据源.多数据源又可以分为两种情况: 1)两个或多个数据库没有相关性,各自独立,其实这种可以作为两个项目来开发.比如在游戏开发中一个数据库是平台数据库,其它还 ...
- 【转】Spring, MyBatis 多数据源的配置和管理
同一个项目有时会涉及到多个数据库,也就是多数据源.多数据源又可以分为两种情况: 1)两个或多个数据库没有相关性,各自独立,其实这种可以作为两个项目来开发.比如在游戏开发中一个数据库是平台数据库,其它还 ...
- mybatis 多数据源动态切换
笔者主要从事c#开发,近期因为项目需要,搭建了一套spring-cloud微服务框架,集成了eureka服务注册中心. gateway网关过滤.admin服务监控.auth授权体系验证,集成了redi ...
- spring boot druid mybatis多数据源
一.关闭数据源自动配置(很关键) @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) 如果不关闭会报异常:o ...
随机推荐
- MySQL树形结构的数据库表设计和查询
1.邻接表(Adjacency List) 实例:现在有一个要存储一下公司的人员结构,大致层次结构如下: 那么怎么存储这个结构?并且要获取以下信息: 1.查询小天的直接上司. 2.查询老宋管理下的直属 ...
- LISTAGG函数
官网进入 该函数作用是可以实现对列值得拼接: 根据官网介绍,可以对列值排序进行拼接,也可以分组拼接 1.1运行结果 1.2运行结果 2运行结果 注意该函数提供的 over( partition by ...
- 5种方法获取url中文件的扩展名
/** * strrchr - 查找指定字符在字符串中的最后一次出现 * strrpos — 计算指定字符串在目标字符串中最后一次出现的位置 * end — 将数组的内部指针指向最后一个单元 * pa ...
- Dart 运行速度测评与比较
引言 Dart 是一门优秀的跨平台语言,尽管生态方面略有欠缺,但无疑作为一门编程语言来说,Dart 是很优美,很健壮的,同时也引入了一些先进的编程范式,值得去学习. 测试内容 现在,我们就来测评一下D ...
- PostgreSQL没有认证密码就登陆了缘由
上午同事爆出这样的问题,使用正确的用户名和错误的密码连接了postgresql数据库,竟然连上了.这不是故意这样神操作,不小心密码写错了,咋一看这样怎么能行,随便输入一个密码都能登陆上.自己测试也是同 ...
- 在WPF(core版本)中引用外部字体不可用问题说明
这几天使用WPF写软件,想引用外部字体,于是下载了字体文件: 然后在App.xaml中添加了如下代码: <FontFamily x:Key="Digital-7 Mono"& ...
- C# 关于位运算的学习笔记
一.理解什么是位运算 程序中的所有内容在计算机内存中都是以二进制的形式储存的(即:0或1),简单来说位运算就是直接对在内存中的二进制数的每位进行运算操作. 二.学习前先了解一下有哪些运算,运算符都怎么 ...
- Python爬虫抓取微博评论
第一步:引入库 import time import base64 import rsa import binascii import requests import re from PIL impo ...
- SSL/TLS 协议运行机制概述(二)
SSL/TLS 协议运行机制概述(二) 在SSL/TLS 协议运行机制概述(一)中介绍了TLS 1.2 的运行机制,现在我们来看年 TLS 1.3 的运行机制.会涉及到SSL/TLS 协议运行机制概述 ...
- 前端BOM和DOM
前端基础之BOM和DOM 前戏 到目前为止,我们已经学过了JavaScript的一些简单的语法.但是这些简单的语法,并没有和浏览器有任何交互. 也就是我们还不能制作一些我们经常看到的网页的一些 ...