一、业务场景

  考虑到新项目中部分与业务数据相关的表在后期数据量会比较大,架构师在最开始设计项目中与业务数据相关的表时,就已经考虑使用分表来

进行处理,给业务数据相关的每张表都添加统一批次的后缀,查询这些数据时,根据不同表名的后缀和来查询对应的数据信息。如果能够动态的

更改数据表,比如将ai_user表更改为ai_user_20220001,这样就可以动态的查询不同表中的数据。

二、需求分析

  最开始考虑使用的是在xml文件中使用if来做条件判断,根据传入参数的不同来动态查询不同的表。这种方式最开始的时候也没什么问题,只是

当需要查询的表非常多的时候,需要写的判断语句也会同样的增多,如果需要改动,则非常不便于进行统一处理。就好比是鉴权,如果在每个请求

的方法中都去写一段鉴权的代码,如果需要进行改动这段代码,那改起来头都大啦。写了几个xml文件后,自己就在考虑能不能像java代码一样,写

一个拦截器之类的,进行统一处理呢?

三、解决方案

  先确定一个大方向,方向确定后就开始去找解决方案,去网上搜索相关的内容,学习资料,查看各种博文等等,需要快速学习,并且实际使用。

这个拦截器需要能够获取到之前的旧有的执行SQL语句,还需要能够获取到执行语句传入的参数,然后根据传入的参数来动态的修改表名,让其生成

新的SQL语句,最后让拦截器执行新的SQL语句即可。这种方式有些类似于PageHelper插件的处理方式,如果改插件检测到需要分页查询的SQL语句,

在就是使用拦截器进行处理,更改需要查询的SQL语句,最终完成分页的查询。

  然后开始不断地探索、尝试,同事最后找到适合的解决方案。示例代码如下,由于是内网开发拿不到源码,只写了示例代码来进行讲解说明.

package mybatis.interceptor;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.util.Map;
import java.util.Properties;

/**
* @Author yilang
* @Description TODO
* @Date 2022/7/7 10:29
* @Version 1.0
*/

@Component
@Intercepts({@Signature(type=StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class MyInterceptor implements Interceptor {

private final static String SOURCE_TABLE = "app_gift_info";

@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaObject = MetaObject.forObject(statementHandler, new DefaultObjectFactory(),
new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
BoundSql boundSql = (BoundSql)metaObject.getValue("delegate.boundSql");
// 获取执行的SQL
String sql = boundSql.getSql();
// 获取执行的SQL参数
//MapperMethod.ParamMap raramMap = (MapperMethod.ParamMap) boundSql.getParameterObject();
//Object param = raramMap.get("param");
Object parameterObject = boundSql.getParameterObject();
String s = JSON.toJSONString(parameterObject);
Map map = JSONObject.parseObject(s, Map.class);

// 替换表名
//String oldTable = (String)map.get("newTable");
Object tempTable = map.get("newTablea");
if (tempTable == null){
tempTable = "";
}
String newTable = (String)tempTable;
if (sql.contains(SOURCE_TABLE)) {
sql = sql.replaceAll(SOURCE_TABLE, newTable);
}
// 替换执行的的SQL.
metaObject.setValue("delegate.boundSql.sql", sql);

return invocation.proceed();
}

@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}

@Override
public void setProperties(Properties properties) {
}
}

说明: @Component 注解:不用多说,用来将当前的自定义Mybatis拦截器注册到Spring容器中,让其进行统一管理。

@Intercepts注解:其value为Signature类数值,注解在Interceptor实现类上,表示实现类对哪些sql执行类(实现Executor)的哪些方法切入

@Signature:表示一个唯一的Interceptor实现类的一个方法,以及入参.可参考这篇文章 https://zhuanlan.zhihu.com/p/286476884

经过反反复复地调试,最终实现自己想要的功能,能够获取到执行的SQL和传入的参数,然后替换SQL中的表,最后执行新的SQL语句。

最后测试发现完全可行。

参考文章-

https://blog.csdn.net/u011625492/article/details/78426628

https://zhuanlan.zhihu.com/p/345438831

https://www.cnblogs.com/blueSkyline/p/10178992.html

测试过程中遇到的问题:在获取SQL执行参数时,如果某个执行方法中只有一个参数,并且没有添加@Param注解时,则转换为map集合会

报类转换异常的错误,这个需要注意。其他参数则可以根据自己的需要进行更改。

拓展:以前的项目中有一个需求,项目需要记录所有执行的SQL语句。这个功能是其他同事的做的,那时自己也很好奇如何完成的,如何实现

的,现在使用了Mybatis的拦截器之后,也明白他是如何处理的啦。只需要在上面的语句中做简单的处理即可实现,非常方便。

mybatis-拦截器实际应用-替换表名-2022新项目的更多相关文章

  1. 无法访问mybatis.dto.StudengInVO-使用maven编译报错-2022新项目

    一.问题由来 最近一次拉代码后,合并代码然后进行编译时出现一个问题,使用maven在进行编译的时候报一个错,无法访问mybatis.dto.StudengInVO. 突然出现这个错误让自己感觉很奇怪, ...

  2. 玩转SpringBoot之整合Mybatis拦截器对数据库水平分表

    利用Mybatis拦截器对数据库水平分表 需求描述 当数据量比较多时,放在一个表中的时候会影响查询效率:或者数据的时效性只是当月有效的时候:这时我们就会涉及到数据库的分表操作了.当然,你也可以使用比较 ...

  3. Mybatis拦截器实现分页

    本文介绍使用Mybatis拦截器,实现分页:并且在dao层,直接返回自定义的分页对象. 最终dao层结果: public interface ModelMapper { Page<Model&g ...

  4. spring hibernate实现动态替换表名(分表)

    1.概述 其实最简单的办法就是使用原生sql,如 session.createSQLQuery("sql"),或者使用jdbcTemplate.但是项目中已经使用了hql的方式查询 ...

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

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

  6. Mybatis拦截器介绍

    拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法.Mybatis拦截器设计的一个初 ...

  7. Mybatis拦截器介绍及分页插件

    1.1    目录 1.1 目录 1.2 前言 1.3 Interceptor接口 1.4 注册拦截器 1.5 Mybatis可拦截的方法 1.6 利用拦截器进行分页 1.2     前言 拦截器的一 ...

  8. "犯罪心理"解读Mybatis拦截器

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

  9. Mybatis拦截器实现原理深度分析

    1.拦截器简介 拦截器可以说使我们平时开发经常用到的技术了,Spring AOP.Mybatis自定义插件原理都是基于拦截器实现的,而拦截器又是以动态代理为基础实现的,每个框架对拦截器的实现不完全相同 ...

随机推荐

  1. 聊聊如何在华为云IoT平台进行产品开发

    摘要:华为云物联网平台承载着南北向数据互通的功能职责. 本文分享自华为云社区<如何基于华为云IoT物联网平台进行产品开发>,作者: Super.雯 . 华为云物联网平台承载着南北向数据互通 ...

  2. vmware ubuntu 忘记密码

    1.进入recovery模式 修改root密码 1.启动ubuntu系统,一开始在有进度条的时候按下shift键,出现GRUB选择菜单,选择Advanced options for Ubuntu 按回 ...

  3. 流量录制回放工具jvm-sandbox-repeater入门篇——服务部署

    趋于当前技术不断更新.产品功能多元化之下,流量回放的热度也是越来越高. 在前一段时间,测试团队也提到阿里开源的流量回放工具 jvm-sandbox-repeater 我个人就先尝试一下,期间还是遇到一 ...

  4. Ansible的参数介绍

    安装完成ansible后查看ansible的参数:ansible -h ansible 命令格式:Usage: ansible <host-pattern> [options] ansib ...

  5. WinUI迁移到即将"过时"的.NET MAUI个人体验

    迁移的初衷 本人平时是做.net相关的工作,对于.net技术栈也有一些了解,自从新的.net能够跨平台之后,之前也有跨平台的ui框架Xamarin,现在微软推出了.NET MAUI这个说是 统一了开发 ...

  6. linux篇-linux面试题汇总

    Linux经典面试题,看看你会几题? 1. 在Linux系统中,以 文件 方式访问设备 . 2. Linux内核引导时,从文件 /etc/fstab 中读取要加载的文件系统. 3. Linux文件系统 ...

  7. css页面样式初始化

    为什么? 同一个样式,在各个浏览器的默认样式可能不同,所以需要统一初始化,同一个页面在不同浏览器能正常显示. @charset "utf-8"; /*css reset*/ bod ...

  8. Ceph集群搭建记录

    环境准备 基础环境 node00 192.168.247.144 node00 node01 192.168.247.135 node01 node02 192.168.247.143 node02 ...

  9. Spring Ioc源码分析系列--容器实例化Bean的四种方法

    Spring Ioc源码分析系列--实例化Bean的几种方法 前言 前面的文章Spring Ioc源码分析系列--Bean实例化过程(二)在讲解到bean真正通过那些方式实例化出来的时候,并没有继续分 ...

  10. 技术分享 | app测试中常用的Android模拟器

    原文链接 Emulator Emualor 是 Android Studio 自带的模拟器,是官方提供的工具,Android 开发最常使用的就是这一款. 它功能非常齐全,电话本.通话等功能都可正常使用 ...