Mybatis多数据源读写分离(注解实现)

#### Mybatis多数据源读写分离(注解实现)
------
首先需要建立两个库进行测试,我这里使用的是master_test和slave_test两个库,两张库都有一张同样的表(偷懒,喜喜),表结构

表名 t_user

| 字段名 | 类型 | 备注 |
| :------: | :------: | :------: |
| id | int | 主键自增ID |
| name | varchar | 名称 |

![file](https://img2018.cnblogs.com/blog/1602984/201909/1602984-20190922132558249-1393771686.jpg)
表中分别添加两条不同数据,方便测试
主数据库记录name为xiaobin,从库为xiaoliu
开始使用Springboot 整合mybatis,首先引入pom文件
```

4.0.0

org.springframework.boot
spring-boot-starter-parent
2.1.4.RELEASE

com.xiaobin
mysql_master_slave
1.0-SNAPSHOT

1.8
1.18.6
1.3.2
1.18.6

org.springframework.boot
spring-boot-starter-web

org.projectlombok
lombok
${lombok.version}

org.springframework.boot
spring-boot-starter-test

org.projectlombok
lombok
${lombox.version}

org.mybatis.spring.boot
mybatis-spring-boot-starter
${mybatis.version}

mysql
mysql-connector-java

org.springframework.boot
spring-boot-starter-jdbc

com.alibaba
druid-spring-boot-starter
1.1.10

org.springframework.boot
spring-boot-starter-aop

```
#### 动态数据源配置
这里使用的数据源为druid,实现数据源之间的切换用@DataSource自定义注解,配置Aop进行切换
application.yml 配置文件
```
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
xiaobin-master: # 主数据源
driverClassName: com.mysql.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/master_test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8
xiaobin-slave: # 从数据源
driverClassName: com.mysql.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/slave_test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8
mybatis:
mapper-locations: classpath:mapper/*.xml

```
#### 多数据源配置类
```
package com.xiaobin.config;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
* 创建时间: 2019/9/22 11:42
* 备注:多数据源配置信息
* 码农自学交流小群:260532022,欢迎大家的加入,分享学习是一件开心事
**/

@Configuration
@Component
public class DynamicDataSourceConfig {

@Bean
@ConfigurationProperties("spring.datasource.druid.xiaobin-master")
public DataSource xiaobinMasterDataSource(){
return DruidDataSourceBuilder.create().build();
}

@Bean
@ConfigurationProperties("spring.datasource.druid.xiaobin-slave")
public DataSource xiaobinSlaveDataSource(){
return DruidDataSourceBuilder.create().build();
}

@Bean
@Primary
public DynamicDataSource dataSource(DataSource xiaobinMasterDataSource, DataSource xiaobinSlaveDataSource) {
Map targetDataSources = new HashMap();
targetDataSources.put("xiaobin-master",xiaobinMasterDataSource);
targetDataSources.put("xiaobin-slave", xiaobinSlaveDataSource);
return new DynamicDataSource(xiaobinMasterDataSource, targetDataSources);
}

}
```

#### 动态数据源切换类
```
package com.xiaobin.config;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.lang.Nullable;

import javax.sql.DataSource;
import java.util.Map;

/**
* 创建时间: 2019/9/22 11:51
* 备注:动态数据源
* 码农自学交流小群:260532022,欢迎大家的加入,分享学习是一件开心事
**/

public class DynamicDataSource extends AbstractRoutingDataSource {

private static final ThreadLocal contextHolder = new ThreadLocal();

public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}

@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}

public static void setDataSource(String dataSource) {
contextHolder.set(dataSource);
}

public static String getDataSource() {
return contextHolder.get();
}

public static void clearDataSource() {
contextHolder.remove();
}
}
```

#### 自定义@DataSource注解
在需要切换数据的Dao添加此注解
```
package com.xiaobin.annotation;

import java.lang.annotation.*;

/**
* 创建时间: 2019/9/22 11:53
* 备注:自定义数据源选择注解
* 码农自学交流小群:260532022,欢迎大家的加入,分享学习是一件开心事
**/

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String name() default "";
}
```

#### Aop切面类配置
```
package com.xiaobin.aspect;

import com.xiaobin.annotation.DataSource;
import com.xiaobin.config.DynamicDataSource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
* 创建时间: 2019/9/22 11:54
* 备注:
* 码农自学交流小群:260532022,欢迎大家的加入,分享学习是一件开心事
**/

@Aspect
@Component
public class DataSourceAspect {

@Pointcut("@annotation(com.xiaobin.annotation.DataSource)")
public void dataSourcePointCut() {

}

@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();

DataSource dataSource = method.getAnnotation(DataSource.class);
if(dataSource == null){
DynamicDataSource.setDataSource("xiaobin-master");
}else {
DynamicDataSource.setDataSource(dataSource.name());
}

try {
return point.proceed();
} finally {
DynamicDataSource.clearDataSource();
}
}
}
```
#### 启动配置注解信息,重要(不然运行会报错)
```
package com.xiaobin;

import com.xiaobin.config.DynamicDataSourceConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Import;

/**
* 创建时间: 2019/9/22 11:17
* 备注:
* 码农自学交流小群:260532022,欢迎大家的加入,分享学习是一件开心事
**/

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@MapperScan(basePackages = "com.xiaobin.mapper")
@Import({DynamicDataSourceConfig.class})
public class StartApp {
public static void main(String[] args) {
SpringApplication.run(StartApp.class);
}
}
```
#### 测试controller
```
package com.xiaobin.api;

import com.xiaobin.Entity.TUser;
import com.xiaobin.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
* 创建时间: 2019/9/22 12:08
* 备注:
* 码农自学交流小群:260532022,欢迎大家的加入,分享学习是一件开心事
**/

@RestController
@RequestMapping
public class UserController {

@Autowired
private UserMapper userMapper;

@GetMapping("/{name}/list")
public List list(@PathVariable("name")String name){
if(name.equals("master")){
return userMapper.queryAllWithMaster();
}else{
return userMapper.queryAllWithSlave();
}
}
}
```
#### 效果图
更具路径传值,进行主从数据源切换
![file](https://img2018.cnblogs.com/blog/1602984/201909/1602984-20190922132558471-1360902101.jpg)
![file](https://img2018.cnblogs.com/blog/1602984/201909/1602984-20190922132558693-1674030148.jpg)
#### 目录结构
![file](https://img2018.cnblogs.com/blog/1602984/201909/1602984-20190922132558939-255963524.jpg)

源码地址(数据库需要自己创建)https://gitee.com/MyXiaoXiaoBin/learning-to-share/tree/master/mysql_master_slave

###### 码农自学交流小群:260532022,欢迎大家的加入,分享学习是一件开心事

原文地址:https://www.cnblogs.com/hy-xiaobin/p/11567144.html

时间: 2024-11-14 06:41:37

Mybatis多数据源读写分离(注解实现)的相关文章

Spring+MyBatis实现数据库读写分离方案

方案1通过MyBatis配置文件创建读写分离两个DataSource,每个SqlSessionFactoryBean对象的mapperLocations属性制定两个读写数据源的配置文件.将所有读的操作配置在读文件中,所有写的操作配置在写文件中. 优点:实现简单缺点:维护麻烦,需要对原有的xml文件进行重新修改,不支持多读,不易扩展实现方式 <bean id="abstractDataSource" abstract="true" class="com

Spring配置动态数据源-读写分离和多数据源

在现在互联网系统中,随着用户量的增长,单数据源通常无法满足系统的负载要求.因此为了解决用户量增长带来的压力,在数据库层面会采用读写分离技术和数据库拆分等技术.读写分离就是就是一个Master数据库,多个Slave数据库,Master数据库负责数据的写操作,slave库负责数据读操作,通过slave库来降低Master库的负载.因为在实际的应用中,数据库都是读多写少(读取数据的频率高,更新数据的频率相对较少),而读取数据通常耗时比较长,占用数据库服务器的CPU较多,从而影响用户体验.我们通常的做法

springboot多数据源读写分离和主库数据源service层事务控制

需求:系统中要实现切换数据库(业务数据库和his数据库) 网上很多资料上有提到AbstractRoutingDataSource,大致是这么说的 在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上. Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性.而这样的方案就会不同

2.配置Spring+SpringMvc+Mybatis(分库or读写分离)--Intellij IDAE 2016.3.5

建立好maven多模块项目后,开始使用ssm传统的框架:http://www.cnblogs.com/yysbolg/p/6898453.html 1.打开总工程下的pom.xml文件:添加如下代码: <!--全局的所有版本号定义--> <properties> <!-- 日志管理 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <logback.

springboot+mybatis实现数据库读写分离

本文不包含数据库主从配置. 实现思路:在项目中配置多数据源,通过代码控制访问哪一个数据源. spring-jdbc为我们提供了AbstractRoutingDataSource,DataSource的抽象实现,基于查找键,返回不通不同的数据源.编写我们自己的动态数据源类DynamicDataSource继承AbstractRoutingDataSource,实现determineCurrentLookupKey方法. 配置一个spring config类DataSourceConfig,把Dyn

mybatis plugins实现项目【全局】读写分离

在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离 注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html mysql主从同步: http://www.cnblogs.com/xiaochangwei/p/4824355.html 如果项目所有读操作和写操作操作不同的数据库,完全读写分离,那么可以简单的通过mybaits的plugins来实现 预计9月底完成

SpringBoot整合MYBATIS,多数据源,事务,支持JAVA -JAR 启动.

用了一段时间SpringBoot,之前配置MYBATIS ,在打包WAR 放到tomcat下正常,但是WAR已经过时了,现在流行直接打包JAR 丢到DOCKER 里,无奈JAR 启动的时候MAPPER 扫描有问题,只能说之前整合MYBATIS 的方式不对. 这次的整合应该是不存在加载顺序引起的问题,使用了一段时间,妥妥的,记录下来 pom.xml <parent> <groupId>org.springframework.boot</groupId> <artif

Mycat - 实现数据库的读写分离与高可用【转】

文章地址:https://www.cnblogs.com/youzhibing/p/9553766.html 前言 开心一刻 上语文课,不小心睡着了,坐在边上的同桌突然叫醒了我,并小声说道:“读课文第三段”.我立马起身大声读了起来.正在黑板写字的老师吓了一跳,老师郁闷的看着我,问道:“同学有什么问题吗?”,我貌似知道了什么,蛋定的说了一句:“这段写的真好!我给大伙念念!”,老师还较真了:“你说说看,好在哪里?”,顿时我就无语了,脸黑着望向了同桌了,心想着:“这是个畜生啊!” 路漫漫其修远兮,吾将

MyBatis多数据源配置(读写分离)

MyBatis多数据源配置(读写分离) 首先说明,本文的配置使用的最直接的方式,实际用起来可能会很麻烦. 实际应用中可能存在多种结合的情况,你可以理解本文的含义,不要死板的使用. 多数据源的可能情况 1.主从 通常是MySql一主多从的情况,本文的例子就是主从的情况,但是只有两个数据源,所以采用直接配置不会太麻烦,但是不利于后续扩展,主要是作为一个例子来说明,实际操作请慎重考虑. 针对这种情况,一个更好的解决方法可以参考(本人没有实际尝试过): http://blog.csdn.net/lixi