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

分库分表 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

四、测试


http://www.kler.cn/a/573411.html

相关文章:

  • 前端埋点项目从设计到实现详解
  • 小程序分类页面
  • Tomcat 是什么?有什么功能和作用?为什么启动 Spring 或 Spring Boot 项目需要 Tomcat?
  • 基于编程语言的建筑行业施工图设计系统开发可行性研究————从参数化建模到全流程自动化的技术路径分析
  • 跳跃游戏||力扣--45
  • 【零基础到精通Java合集】第二十九集:SQL常用优化手段
  • 雷军曝光小米影像外挂,大镜头吸附,手机变单反
  • 山东大学计算机科学与技术学院软件工程实验日志
  • Spring IoC配置(xml+FactoryBean)
  • doris: PostgreSQL
  • 极狐GitLab 17.9 正式发布,40+ DevSecOps 重点功能解读【三】
  • gmock和cppfreemock原理学习
  • 统计建模小贴士
  • CC++链接数据库(MySQL)超级详细指南
  • Rust编程实战:Rust实现简单的Web服务,单线程性能问题
  • CHAPTER 6 Object References, Mutability, and Recycling
  • ARM 架构下 cache 一致性问题整理
  • CAD2025电脑置要求
  • MySQL篇:基础知识总结与基于长期主义的内容更新
  • 使用Docker搭建Oracle Database 23ai Free并扩展MAX_STRING_SIZE的完整指南