在大数据高并发的应用场景下,为了更快的响应用户请求,读写分离是比较常见的应对方案。读写分离会使用多数据源的使用。下面记录如何搭建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 多数据源动态配置的更多相关文章

  1. Springboot+Mybatis+Pagehelper+Aop动态配置Oracle、Mysql数据源

      本文链接:https://blog.csdn.net/wjy511295494/article/details/78825890 Springboot+Mybatis+Pagehelper+Aop ...

  2. springboot2.0+mybatis多数据源集成

    最近在学springboot,把学的记录下来.主要有springboot2.0+mybatis多数据源集成,logback日志集成,springboot单元测试. 一.代码结构如下 二.pom.xml ...

  3. springboot2.1+redis多数据源的配置

    springboot系列学习笔记全部文章请移步值博主专栏**: spring boot 2.X/spring cloud Greenwich.    由于是一系列文章,所以后面的文章可能会使用到前面文 ...

  4. spring-boot 速成(9) druid+mybatis 多数据源及读写分离的处理

    按上节继续学习,稍微复杂的业务系统,一般会将数据库按业务拆开,比如产品系统的数据库放在product db中,订单系统的数据库放在order db中...,然后,如果量大了,可能每个库还要考虑做读.写 ...

  5. spring+mybatis多数据源动态切换

    spring mvc+mybatis+多数据源切换 选取oracle,mysql作为例子切换数据源.oracle为默认数据源,在测试的action中,进行mysql和oracle的动态切换. web. ...

  6. Spring, MyBatis 多数据源的配置和管理

    同一个项目有时会涉及到多个数据库,也就是多数据源.多数据源又可以分为两种情况: 1)两个或多个数据库没有相关性,各自独立,其实这种可以作为两个项目来开发.比如在游戏开发中一个数据库是平台数据库,其它还 ...

  7. 【转】Spring, MyBatis 多数据源的配置和管理

    同一个项目有时会涉及到多个数据库,也就是多数据源.多数据源又可以分为两种情况: 1)两个或多个数据库没有相关性,各自独立,其实这种可以作为两个项目来开发.比如在游戏开发中一个数据库是平台数据库,其它还 ...

  8. mybatis 多数据源动态切换

    笔者主要从事c#开发,近期因为项目需要,搭建了一套spring-cloud微服务框架,集成了eureka服务注册中心. gateway网关过滤.admin服务监控.auth授权体系验证,集成了redi ...

  9. spring boot druid mybatis多数据源

    一.关闭数据源自动配置(很关键) @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) 如果不关闭会报异常:o ...

随机推荐

  1. Python-添加psutil模块到python2.7版本

    一.问题描述 1.导入模块psutil时提示报错:ImportError: No module named psutil 2.下载psutil模块后,安装python setup.py install ...

  2. Python神经网络编程笔记

    神经元 想一想便知道,当一个人捏你一下以至于你会痛得叫起来的力度便是神经元的阈值,而我们构建的时候也是把这种现象抽象成一个函数,叫作激活函数. 而这里便是我们使用sigmoid函数的原因,它是一个很简 ...

  3. UVA - 10462 Is There A Second Way Left?

    题意: 给你一张无向图,让你判断三种情况:1.不是连通图(无法形成生成树)2.只能生成唯一的生成树 3.能生成的生成树不唯一(有次小生成树),这种情况要求出次小生成树的边权值和. 思路: 比较常见的次 ...

  4. 日常破解--从XCTF的app3题目简单了解安卓备份文件以及sqliteCipher加密数据库

    一.题目来源     题目来源:XCTF app3题目 二.解题过程     1.下载好题目,下载完后发现是.ab后缀名的文件,如下图所示:     2.什么是.ab文件?.ab后缀名的文件是Andr ...

  5. MapReduce 简单数据统计

    1. 准备数据源 摘录了一片散文,保存格式为utf-8 2. 准备环境 2.1 搭建伪分布式环境 https://www.cnblogs.com/cjq10029/p/12336446.html 上传 ...

  6. python3编写程序,实现打印100以内的素数。

    代码如下: for x in range(2, 100): for y in range(2, x): if x % y == 0: break else: print(x, end="\t ...

  7. 2020ubuntu1804server编译安装redis5笔记(二)配置redis

    前一篇笔记记录了ubuntu1804server编译安装redis5,接下来要配置redis5了 网址:https://www.cnblogs.com/qumogu/p/12435694.html 第 ...

  8. docker学习之路

    环境 : ubuntu 16.4 下载docker 首先使用命令行下载 docker wget -qO- https://get.docker.com/ | sh 启动 下载完成之后进行一个启动,但是 ...

  9. Chrome开发者工具之测试应用

    一.Chrome开发者工具简介 浏览器的开发者工具(DevTools)可以帮助开发人员对网页进行布局,比如HTML+CSS,帮助前端工程师更好的调试脚本(JavaScript.jQuery)之类的,还 ...

  10. vue中moment.js的使用

    一.介绍 moment.js是一款现在对时间处理的强大的函数. Moment被设计用于在浏览器和Node.js中工作. 目前ci系统使用的浏览器有:IE8.IE9在Windows 7上.Chrome在 ...