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

devtools/2025/3/6 17:47:35/

一、定义拦截器

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;}@Overridepublic 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);// 设置回MetaObjectmetaObject.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;@Beanpublic MybatisPlusInterceptor dynamicTableNameInnerInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new DynamicTableNameInterceptor(tableLibrary));return interceptor;}
}

三、配置文件修改

# 分表库
tableLibrary: asm_result,check_result

四、测试


http://www.ppmy.cn/devtools/165045.html

相关文章

【C++设计模式】第一篇:单例模式(Singleton)​

注意&#xff1a;复现代码时&#xff0c;确保 VS2022 使用 C17/20 标准以支持现代特性。 确保全局唯一实例的线程安全实现 1. 模式定义与用途​ 核心目标&#xff1a;保证一个类仅有一个实例&#xff0c;并提供全局访问点。 常见场景&#xff1a; 日志系统&#xff08;避免多…

Ubuntu20.04 在离线机器上安装 NVIDIA Container Toolkit

步骤 1.下载4个安装包 Index of /nvidia-docker/libnvidia-container/stable/ nvidia-container-toolkit-base_1.13.5-1_amd64.deb libnvidia-container1_1.13.5-1_amd64.deb libnvidia-container-tools_1.13.5-1_amd64.deb nvidia-container-toolkit_1.13.5-1_amd64.deb 步…

spring-ioc-bean

本文重点在于充分应用 Spring 提供的 IoC 特性&#xff0c;介绍如何创建一个好用的 Bean。基础篇不涉及后置处理器、 BeanDefinition 以及 Spring 加载原理相关的知识。 引入 ioc 的起源 ** 接口与实现类的需求变更 ** &#xff1a;最初的静态工厂模式。** 反射机制 ** &…

Unix Domain Socket和eventfd

在Linux开发中&#xff0c;Unix Domain Socket和eventfd是两种不同的通信机制&#xff0c;它们的设计目标和适用场景有显著差异。以下分点解释并配合示例说明&#xff1a; 一、Unix Domain Socket&#xff08;UDS&#xff09; 1. 是什么&#xff1f; 一种**本地进程间通信&am…

【数据库】关系代数

关系代数 一、关系代数的概念二、关系代数的运算2.1 并、差、交2.2 投影、选择2.3 笛卡尔积2.4 连接2.5 重命名2.6 优先级 一、关系代数的概念 关系代数是一种抽象的数据查询语言用对关系的运算来表达查询 运算对象&#xff1a;关系运算符&#xff1a;4类运算结果&#xff1a;…

大白话html第五章HTML5 新增表单元素和属性

大白话html第五章HTML5 新增表单元素和属性 HTML5 给表单带来了很多新的小伙伴&#xff0c;让我们收集用户信息变得更方便、更智能。 新增表单元素 <input type"date">&#xff1a;这个就像一个自带日历的小框框&#xff0c;用户可以直接在里面选择日期&…

11 Oracle Golden Gate 高可用解决方案:Golden Gate 助力企业保障业务连续性

文章目录 Oracle Golden Gate 高可用解决方案&#xff1a;Golden Gate 助力企业保障业务连续性一、Oracle Golden Gate基本概念二、设计异地灾备策略2.1 需求分析2.2 网络规划2.3 部署架构 三、实施异地灾备策略3.1 环境准备3.2 配置Golden Gate3.3 验证与测试 四、数据保护策略…

Mac mini M4安装nvm 和node

先要安装Homebrew&#xff08;如果尚未安装&#xff09;。在终端中输入以下命令&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 根据提示操作完成Homebrew的安装。 安装nvm。在终端中输入以下命令&#xf…