多数据源的应用场景比较多,前面已经分享了几种,今天我再通过拦截器的角度分享一次,这样也更贴近实战,更准确,今天主要验证拦截器,比如读写分离的场景,在拦截器接口判断此条接口是查询还是修改,如果是查询赋值读库的数据源,如果是修改就赋值写库的数据库,这样也能精准的处理读写分离的业务问题。废话少数,下面咱们开始:

1、pom文件引入相关jar:

       <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</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.2.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--Druid连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.8</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>

2、数据库配置,暂定两个固定数据库:

spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcemaster-db:url: jdbc:mysql://127.0.0.1:3306/master-db?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF8&useSSL=falseusername: rootpassword: rootinitial-size: 1min-idle: 1max-active: 20test-on-borrow: truedriver-class-name: com.mysql.cj.jdbc.Driverslave-db:url: jdbc:mysql://127.0.0.1:3306/slave-db?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF8&useSSL=falseusername: rootpassword: rootinitial-size: 1min-idle: 1max-active: 20test-on-borrow: truedriver-class-name: com.mysql.cj.jdbc.Driver

3、数据库初始化配置类

package com.nandao.dynamic.datasource.config;import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.nandao.dynamic.datasource.DynamicDataSource;
import com.nandao.dynamic.datasource.plugin.DynamicDataSourcePlugin;
import org.apache.ibatis.plugin.Interceptor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;/**** @Author nandao*/
@Configuration
public class DataSourceConfig {@Bean@ConfigurationProperties(prefix = "spring.datasource.master-db")public DataSource dataSource1() {// 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSourcereturn DruidDataSourceBuilder.create().build();}@Bean@ConfigurationProperties(prefix = "spring.datasource.slave-db")public DataSource dataSource2() {// 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSourcereturn DruidDataSourceBuilder.create().build();}@Bean//或者在DynamicDataSourcePlugin类上添加@Component注解public Interceptor dynamicDataSourcePlugin(){return new DynamicDataSourcePlugin();}@Beanpublic DataSourceTransactionManager transactionManager1(DynamicDataSource dataSource){DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();dataSourceTransactionManager.setDataSource(dataSource);return dataSourceTransactionManager;}@Beanpublic DataSourceTransactionManager transactionManager2(DynamicDataSource dataSource){DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();dataSourceTransactionManager.setDataSource(dataSource);return dataSourceTransactionManager;}
}

4、定义多数据源的实现类

package com.nandao.dynamic.datasource;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;/**** @Author nandao*/
@Component
@Primary   // 将该Bean设置为主要注入Bean
public class DynamicDataSource extends AbstractRoutingDataSource {// 当前使用的数据源标识public static ThreadLocal<String> name = new ThreadLocal<>();// 写@AutowiredDataSource dataSource1;// 读@AutowiredDataSource dataSource2;// 返回当前数据源标识@Overrideprotected Object determineCurrentLookupKey() {return name.get();}@Overridepublic void afterPropertiesSet() {// 为targetDataSources初始化所有数据源Map<Object, Object> targetDataSources=new HashMap<>();targetDataSources.put("W",dataSource1);targetDataSources.put("R",dataSource2);super.setTargetDataSources(targetDataSources);// 为defaultTargetDataSource 设置默认的数据源super.setDefaultTargetDataSource(dataSource1);super.afterPropertiesSet();}
}

5、自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/**** @Author nandao*/
@Target({ElementType.METHOD,ElementType.TYPE})
// 方式
@Retention(RetentionPolicy.RUNTIME)
public @interface WR {String value() default "W";
}

6、切面实现拦截数据源

package com.nandao.dynamic.datasource.aspect;import com.nandao.dynamic.datasource.DynamicDataSource;
import com.nandao.dynamic.datasource.annotation.WR;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;/**** @Author nandao*/
@Component
@Aspect
public class DynamicDataSourceAspect implements Ordered {// 前置@Before("within(com.nandao.dynamic.datasource.service.impl.*) && @annotation(wr)")public void before(JoinPoint point, WR wr){String name = wr.value();DynamicDataSource.name.set(name);System.out.println(name);}@Overridepublic int getOrder() {return -1;}
}

7、mybatis的拦截器处理数据源

package com.nandao.dynamic.datasource.plugin;import com.nandao.dynamic.datasource.DynamicDataSource;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;import java.util.Properties;/**** @Author nandao*/
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class,ResultHandler.class})})
@Component // 或者在配置类里添加一个@Bean对象
public class DynamicDataSourcePlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 拿到当前方法(update、query)所有参数Object[] objects = invocation.getArgs();// MappedStatement 封装CRUD所有的元素和SQLMappedStatement ms = (MappedStatement) objects[0];// 读方法if (ms.getSqlCommandType().equals(SqlCommandType.SELECT)) {DynamicDataSource.name.set("R");} else {// 写方法DynamicDataSource.name.set("W");}return invocation.proceed();}@Overridepublic Object plugin(Object target) {if (target instanceof Executor) {return Plugin.wrap(target, this);} else {return target;}}@Overridepublic void setProperties(Properties properties) {}
}

8、业务伪代码参考

控制层:

package com.nandao.dynamic.datasource.controller;import com.nandao.dynamic.datasource.entity.Frend;
import com.nandao.dynamic.datasource.service.FrendService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/**** @Author nandao*/
@RestController
@RequestMapping("frend")
@Slf4j
public class FrendController {@Autowiredprivate FrendService frendService;@GetMapping(value = "select")public List<Frend> select(){return frendService.list();}@GetMapping(value = "insert")public void in(){Frend frend = new Frend();frend.setName("南道");frendService.save(frend);}
}

业务层:

package com.nandao.dynamic.datasource.service.impl;import com.nandao.dynamic.datasource.annotation.WR;
import com.nandao.dynamic.datasource.mapper.FrendMapper;
import com.nandao.dynamic.datasource.entity.Frend;
import com.nandao.dynamic.datasource.service.FrendService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/**** @Author nandao*/
@Service
public class FrendImplService implements FrendService {@AutowiredFrendMapper frendMapper;@Override@WR("R")        //读库public List<Frend> list() {return frendMapper.list();}@Override@WR("W")        // 写库public void save(Frend frend) {frendMapper.save(frend);}
}

mapper层:

package com.nandao.dynamic.datasource.mapper;import com.nandao.dynamic.datasource.entity.Frend;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;import java.util.List;/*** @Auther nandao*/
public interface FrendMapper   {@Select("SELECT * FROM Frend")List<Frend> list();@Insert("INSERT INTO  frend(`name`) VALUES (#{name})")void save(Frend frend);
}

postman测试完验证多数据源无误!在实际使用过程,mybtais 拦截器和AOP切面方式二选一。

到此,今天的多数据源分享完毕,多数据源分享暂时告一段落,下期我们分析mybatis的源码,敬请期待!

从mybatis拦截器维度处理读写分离的多数据源问题相关推荐

  1. MySQL拦截器获取xml id_关于mybatis拦截器,有谁知道怎么对结果集进行拦截,将指定字段查询结果进行格式化...

    用MyBatis结果集拦截器做过这样一个需求: 由于项目需求经常变动,项目MySQL数据库都是存放JSON字符串,例如:用户的基本信息随着版本升级可能会有变动 数据表 CREATE TABLE `ac ...

  2. list mybatis 接收 类型_基于mybatis拦截器实现的一款简易影子表自动切换插件

    近期因工作需要,小编基于mybatis拦截器开发了一款简易影子表自动切换插件,可以根据配置实现动态修改表名,即将对原source table表的操作自动切换到对target table表的操作.该插件 ...

  3. 面试官:你能说说MyBatis拦截器原理吗?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:Format cnblogs.com/fangjian042 ...

  4. 犯罪心理解读Mybatis拦截器

    原文链接:"犯罪心理"解读Mybatis拦截器 Mybatis拦截器执行过程解析 文章写过之后,我觉得 "Mybatis 拦截器案件"背后一定还隐藏着某种设计动 ...

  5. MyBatis拦截器原理探究MyBatis拦截器原理探究

    MyBatis拦截器介绍 MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能.那么拦截器拦截MyBatis中的哪些内容呢? 我们进入官网看一看: MyBatis拦截 ...

  6. MyBatis拦截器有哪些以及分析

    MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能.那么拦截器拦截MyBatis中的哪些内容呢? 我们进入官网看一看: MyBatis 允许你在已映射语句执行过程中 ...

  7. Mybatis拦截器 mysql load data local 内存流处理

    Mybatis 拦截器不做解释了,用过的基本都知道,这里用load data local主要是应对大批量数据的处理,提高性能,也支持事务回滚,且不影响其他的DML操作,当然这个操作不要涉及到当前所lo ...

  8. MyBatis拦截器原理探究

    MyBatis拦截器介绍 MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能.那么拦截器拦截MyBatis中的哪些内容呢? 我们进入官网看一看: MyBatis 允 ...

  9. insert into select 主键自增_springboot2结合mybatis拦截器实现主键自动生成

    点击上方蓝字关注我们 1 01 前言 前阵子和朋友聊天,他说他们项目有个需求,要实现主键自动生成,不想每次新增的时候,都手动设置主键.于是我就问他,那你们数据库表设置主键自动递增不就得了.他的回答是他 ...

最新文章

  1. ES6中的异步对象Promise
  2. python数据分析的主要流程-Python数据分析全流程实操指南
  3. python综合学习一之多线程
  4. tom大叔blog--------深入理解javascript系列-----------笔记
  5. postgres 禁止远程登录_Windows 7禁止可移动存储设备写入数据,只有想不到,没有做不到...
  6. 狗窝里的小日子- 4 ...
  7. 交换最小值和最大值 (15 分)
  8. echarts树图节点垂直间距_铝模板的安装、拆除、节点、禁止做法详解
  9. memcached构建高性能web应用
  10. 跟我一起来用C++写Web服务器吧
  11. 打印当前html页面 有背景,word打印时页面背景颜色怎么去掉
  12. IP-Guard十六个模块功能详解
  13. 5G手机占比逼近四成,华为和小米将加速5G普及
  14. 解决msvcr120.dll文件丢失问题(搞了半天,简直奔溃,最后完美解决)
  15. 如何利用迅雷来下载百度云文件?(此方法只适用于大文件需要启动百度网盘的客户端这种情况)...
  16. 计算机配置中什么表示硬盘,电脑硬盘的分类介绍 硬盘中的Master和Slave代表什么意思...
  17. 《江山美人》:程小东的利落与编剧群的故步自封
  18. 掘金 AMA:听闲鱼客户端架构师--邬吉风聊 Flutter 和移动端开发那些事
  19. OA系统实现(请假审批,mybatis)-2
  20. S2SH水费管理系统-JAVA【数据库设计、源码、开题报告】

热门文章

  1. 懂我的人不需要我解释,不懂我的人我不需要解释。。
  2. 将 top命令执行结果输出到文件
  3. python体验课是上纯代码_大陈教初中生学Python,入门体验第二课教学设计,溯本追源...
  4. HTML2Canvas---合成海报遇到问题总结
  5. 玩转STM32F0 Value Line Discovery 之 时钟配置工具
  6. 在字符串中查找子字符串
  7. 英语学习打卡-美国语文1-4
  8. autojs健康天天报(企业微信)——JZU
  9. TCL爱奇艺再次联姻 共同打造国际微电影节
  10. 浙江工业大学电子计算机专业,浙江工业大学计算机专业怎么样