当前位置: 首页 > news >正文

分库分表 MyBatis的拦截器(Interceptor)在 SQL 执行前动态修改表名

一、定义拦截器

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import java.math.BigDecimal;
import java.sql.Connection;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Intercepts({ })
 * 这个注解用于标记一个类是一个MyBatis拦截器。
 * 它包含一个或多个@Signature注解,用于指定拦截的目标方法。
 */
@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
@Slf4j
public class DynamicTableNameInterceptor implements InnerInterceptor {
    private String tableLibrary;

    public DynamicTableNameInterceptor(String tableLibrary) {
        this.tableLibrary = tableLibrary;
    }

    @Override
    public void beforePrepare(StatementHandler statementHandler, Connection connection, Integer transactionTimeout) {
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);// MetaObject 是MyBatis提供的一个工具类,用于通过反射操作对象的属性
        BoundSql boundSql = statementHandler.getBoundSql();

        String sql = boundSql.getSql();// 获取原始SQL语句
        Object parameterObject = boundSql.getParameterObject();// 获取参数对象

        String custom = null;
        String customYear = null;

        if (parameterObject instanceof Map) {

            Map<String, Object> paramMap = (Map<String, Object>) parameterObject;
            customYear = paramMap.containsKey("customYear") ? (String) paramMap.get("customYear") : null;
            custom = paramMap.containsKey("custom") ? (String) paramMap.get("custom") : null;

        } else if(

                !(parameterObject instanceof String)
                && !(parameterObject instanceof Integer)
                && !(parameterObject instanceof Long)
                && !(parameterObject instanceof Double)
                && !(parameterObject instanceof BigDecimal)
                && !(parameterObject instanceof Date)
                && !(parameterObject instanceof Boolean)
        ) {

            JSONObject json = new JSONObject(parameterObject);
            customYear = json.containsKey("customYear") ? (String) json.get("customYear") : null;
            custom = json.containsKey("custom") ? (String) json.get("custom") : null;

        }
        // custom为true表示不需要替换表名
        if("true".equals(custom)){
            return;
        }

        String replaceYear;
        if (StringUtils.isEmpty(customYear)) {
            replaceYear = String.valueOf(DateUtil.year(new Date()));// 获取当前年份
        } else {
            replaceYear = customYear;
        }
        
        String modifiedSql = modifyTableName(sql,replaceYear);
        
        // 设置回MetaObject
        metaObject.setValue("delegate.boundSql.sql", modifiedSql);
    }

    /**
     * 替换表名
     * @param sql 需要替换的 SQL
     * @param replaceYear 表名的年份
     * @return modifiedSql 替换之后的 SQL
     */
    private String modifyTableName(String sql,String replaceYear) {
        String modifiedSql = sql;
        List<String> tableLibraries = Arrays.asList(tableLibrary.split(","));
        if (!CollectionUtils.isEmpty(tableLibraries)) {

            for (String table : tableLibraries) {
                String newTableName = table + "_" + replaceYear;// 构造新表名
                modifiedSql = modifiedSql.replace(table, newTableName); // modifiedSql中存放修改之后的sql
            }
        }
        return modifiedSql;
    }
}

二、注册拦截器

@Configuration
public class MybatisPlusConfig {
    @Value("${tableLibrary:}")
    private String tableLibrary;

    @Bean
    public MybatisPlusInterceptor dynamicTableNameInnerInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new DynamicTableNameInterceptor(tableLibrary));
        return interceptor;
    }
}

三、配置文件修改

# 分表库
tableLibrary: asm_result,check_result

四、测试

相关文章:

  • 系统架构评估中的重要概念
  • java数据结构_再谈String_10
  • 索引(MySQL)
  • C# iText 抽取PDF页特定区域文本内容
  • MySQL:MySQL的数据类型
  • Autojs无线连接vscode方法
  • 【JAVA架构师成长之路】【持久层】第2集:SQL常用优化手段
  • 高精算法的用法及其优势
  • PHP之数组
  • Java 多线程
  • 初识Qt · 信号与槽 · 基础知识
  • 计算机视觉算法实战——图像分割(主页有源码)
  • 【FFmpeg之如何新增一个硬件解码器】
  • LeetCode 双指针章节
  • 【Spring AOP】_切点类的切点表达式
  • 安装IK分词器;IK分词器配置扩展词库:配置扩展字典-扩展词,配置扩展停止词字典-停用词
  • 【工具】COME对比映射学习用于scRNA-seq数据的空间重构
  • 通过HTML有序列表(ol/li)实现自动递增编号的完整解决方案
  • 基于遗传算法的无人机三维路径规划仿真步骤详解
  • GStreamer —— 2.3、Windows下Qt加载GStreamer库后运行 - “教程3:动态管道“(附:完整源码)
  • 网站建设 费用/软件推广平台
  • 公司网站建设升上去/电商培训有用吗
  • 网站建设色系搭配/网络营销心得体会300字
  • 南京建设工程网站/营销型网站有哪些
  • 网站 备案 哪个省/搜狗站长平台主动提交
  • 莱芜车管所网站/一呼百应推广平台