mybatis项目实现动态表名方法总结

实现动态表名是个很常见的需求,网上也有很多解决方法,这边总结了三种实现方式。

一、手动给每个方法加个表名的变量

缺点很明显,侵入性大,不方便,不推荐

二、mybatis插件机制拦截sql替换表名实现动态表名

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

/**
 * mybatis插件实现动态表名,可以拦截器新增、编辑、删除、查询等
 */
@Component
@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {
                Connection.class, Integer.class})})
public class ReplaceTablePlugin implements Interceptor {

    private static final Logger LOG = LoggerFactory.getLogger(ReplaceTablePlugin.class);

    private final static Map TABLE_MAP = new LinkedHashMap<>();

    /**
     * 需要替换的表(替换前的表名和替换后的表名)
     */
    static {
        TABLE_MAP.put("t_user", "t_user_20220101");
        TABLE_MAP.put("t_org", "t_org_20220202");
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = realTarget(invocation.getTarget());
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        doTable(statementHandler, metaObject);
        return invocation.proceed();
    }

    private void doTable(StatementHandler handler, MetaObject metaStatementHandler) throws ClassNotFoundException {
        BoundSql boundSql = handler.getBoundSql();
        String originalSql = boundSql.getSql();
        if (originalSql != null && !originalSql.equals("")) {
            LOG.info("拦截前的sql:{}", originalSql);
            if (isReplaceTableName(originalSql)) {
                for (Map.Entry entry : TABLE_MAP.entrySet()) {
                    originalSql = originalSql.replace(entry.getKey(), entry.getValue());
                }
                LOG.info("拦截后的sql:{}", originalSql);
                metaStatementHandler.setValue("delegate.boundSql.sql", originalSql);
            }
        }
    }

    private boolean isReplaceTableName(String sql) {
        for (String tableName : TABLE_MAP.keySet()) {
            if (sql.contains(tableName)) {
                return true;
            }
        }
        return false;
    }

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

    @Override
    public void setProperties(Properties properties) {
    }

    /**
     * Obtain real processing objects, possibly multi-layer agents
     *
     * @param target
     * @param
     * @return
     */
    public static  T realTarget(Object target) {
        if (Proxy.isProxyClass(target.getClass())) {
            MetaObject metaObject = SystemMetaObject.forObject(target);
            return realTarget(metaObject.getValue("h.target"));
        }
        return (T) target;
    }
}

需要注意的是,mybatis的interceptor无法直接注入类,需要这样写

ApplicationContext applicationContext = SpringContextHolder.getApplicationContext();
XXXXX XXXXX= (XXXXX) applicationContext.getBean(XXXXX.class);

三、mybatis-plus的DynamicTableNameInnerInterceptor实现

3.1引入mybatis-plus的pom jar包依赖

<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-extensionartifactId>
    <version>3.5.2version>
dependency>
<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-annotationartifactId>
    <version>3.5.2version>
dependency>
<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-coreartifactId>
    <version>3.5.2version>
dependency>

3.2 实现的配置类

import java.util.Map;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.redis.core.RedisTemplate;

/**
*
* mybatis-plus实现动态替换表名
*/
@MapperScan("com.xiaweiyi8080.dal.mapper")
@ComponentScan({"com.xiaweiyi8080.dal.manager"})
@Slf4j
public class MyBatisPlusConfiguration {

    @Autowired
    private RedisTemplate redisTemplate;

    // 配置文件里配置的哪些表需要动态表名
    @Value("${xxxxx.tableName:}")
    private String dynamicTableName;

    @Bean
    public MybatisPlusInterceptor dynamicTableNameInterceptor() {
        log.info("------拿到的dynamicTableName={}", dynamicTableName);
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
        dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
            // 获取参数方法
            Map paramMap = RequestDataHelper.getRequestData();
            if (CollectionUtil.isNotEmpty(paramMap)) {
                paramMap.forEach((k, v) -> log.info(k + "----" + v));
            }
            if (StringUtils.isNotBlank(dynamicTableName) && dynamicTableName.contains(tableName)) {
                log.info("------替换前表名={}", tableName);
                String suffix = "_20220101";
                tableName += suffix;
                log.info("------替换后表名={}", tableName);
            }
            return tableName;
        });
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
        return interceptor;
    }

}

Original: https://www.cnblogs.com/shamo89/p/16516884.html
Author: 夏威夷8080
Title: mybatis项目实现动态表名方法总结

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/543441/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 常用日期/时间格式化字符

    常用日期/时间格式化字符: 字符格式 日期格式 yyyy年MM月dd日 HH时mm分ss秒 EEEE 月份英文简写: MMM 月份英文全拼:MMMM 第q季度 a c 2017年0…

    Java 2023年6月9日
    081
  • mysql 常用函数

    CONCAT(s1,s2) 例子:SELECT CONCAT (“SQL “,”Runoob “,”Gooogle &#…

    Java 2023年6月5日
    053
  • linux 映射windows 下的共享文件夹

    linux 映射windows 下的共享文件夹 本文讯】2021年4月27日 在对接第三方系统,进行数据采集的时候,对方给了我们一个文件夹,里面全是txt文件,这个时候就要想办法获…

    Java 2023年6月16日
    069
  • 记录eclipse中文出现空格宽度不一致的bug

    起因 不久前更新了 eclipse(2019-03) 版本;突然发现出现了,使用注释使用中出现的空格的间隔大小不一致的问题,具体可以看下图: 遇到这种问题简直逼不能忍,在网上搜一下…

    Java 2023年6月10日
    0105
  • 55.不舍

    dsfds posted @2022-09-28 08:31 随遇而安== 阅读(5 ) 评论() 编辑 Original: https://www.cnblogs.com/55z…

    Java 2023年6月7日
    067
  • 形参与实参的定义与区别

    博客园 :当前访问的博文已被密码保护 请输入阅读密码: Original: https://www.cnblogs.com/SuperAx/p/13177798.htmlAutho…

    Java 2023年6月5日
    077
  • mybatis学习笔记(一)for 概念

    mybaits相关概念 1.1 mybatis简介 mybatis是是一款优秀的基于ORM的半自动轻量级持久层框架,它支持定制化SQL、存储过程以及高级映射。(与另一基于ORM的持…

    Java 2023年6月5日
    084
  • 实体类null属性滤除

    背景:用一个实体类传输数据的过程中,经常会有部分属性不需要传值,但是还是传到前端,但是显示的值为null,影响美观 需求:用实体传输时,有值的属性传,没有值的属性进行滤除 实现: …

    Java 2023年6月8日
    042
  • Django 前后台的数据传递

    Django 从后台往前台传递数据时有多种方法可以实现。 最简单的后台是这样的: 这个就是返回index.html的内容,但是如果要带一些数据一起传给前台的话,该怎么办呢? 这里是…

    Java 2023年5月29日
    067
  • 关于 jdk1.8 时间处理的方法(实用)

    package avg.position.zhangdi; import java.text.ParseException; import java.text.SimpleDate…

    Java 2023年5月30日
    063
  • IaaS/ PaaS/ SaaS

    PaaS(平台即服务) 如 低代码平台IaaS (基础架构即服务) 如 阿里云主机SaaS (软件即服务) 如 淘宝之于卖家 Original: https://www.cnblo…

    Java 2023年6月15日
    068
  • 【java并发核心一】Semaphore 的使用思路

    最近在看一本书《Java并发编程 核心方法与框架》,打算一边学习一边把学习的经验记下来,所粘贴的代码都是我运行过的,大家一起学习,欢迎吐槽。 估计也没多少人看我的博客,哈哈,那么我…

    Java 2023年5月29日
    087
  • 2018年最新JAVA面试题总结之框架(4)

    转自于:https://zhuanlan.zhihu.com/p/40098726 1、谈谈对spring框架的了解 ,spring有什么作用(IOC,AOP),spring的核心…

    Java 2023年6月13日
    087
  • Spring Cloud系列之Eureka使用详解

    1 简介 Spring Cloud Eureka是 Spring Cloud Netflix项目下的服务治理模块。 Netflix完整的服务治理包括:服务发现(Eureka),断路…

    Java 2023年6月8日
    074
  • Java中如何快捷的创建不可变集合

    在Java 9中又新增了一些API来帮助便捷的创建不可变集合,以减少代码复杂度。 常规写法 以往我们创建一些不可变集合的时候,通常是这样写的: // 不可变的Set Set set…

    Java 2023年6月9日
    068
  • 序列化表单为json对象,datagrid带额外参提交一次查询 后台用Spring data JPA 实现带条件的分页查询 多表关联查询

    查询窗口中可以设置很多查询条件 表单中输入的内容转为datagrid的load方法所需的查询条件向原请求地址再次提出新的查询,将结果显示在datagrid中 转换方法看代码注释 &…

    Java 2023年5月30日
    0115
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球