MyBatis-Plus 动态分表实战:基于 DynamicTableNameInnerInterceptor 的多端数据隔离方案

一、概述

本项目基于 MyBatis-Plus DynamicTableNameInnerInterceptor 实现动态分表,核心思路是:在 SQL 执行前,通过 ThreadLocal 传递表名后缀,拦截器自动将逻辑表名替换为物理表名,从而实现多端数据隔离(如微信端 t_product_wechat、Web 端 t_product_web)。

二、核心类职责

类 路径 职责
ShardInteConfig biz/config/ShardInteConfig.java 配置类,注册拦截器并绑定 Handler
TableShardHandler biz/handle/TableShardHandler.java 拦截器回调,执行表名拼接
DataShardStrategyHelper biz/handle/DataShardStrategyHelper.java ThreadLocal 工具类,存取/清除后缀
ShardTableConfig biz/config/properties/ShardTableConfig.java 配置属性,定义默认后缀值

三、调用链路

scss 复制代码
业务方法 → setShardType(type) → setShardingTableSuffix(suffix)
                                    ↓ (ThreadLocal 存储)
                         MyBatis 执行 SQL
                                    ↓
              DynamicTableNameInnerInterceptor 拦截
                                    ↓
              TableShardHandler.dynamicTableName(sql, tableName)
                                    ↓
              tableName + "_" + suffix  →  实际物理表名
                                    ↓
                         业务方法 finally → clearShardType()

四、各层详细逻辑

4.1 配置层

java 复制代码
@Bean("shardingMybatisPlusInterceptor")
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    DynamicTableNameInnerInterceptor interceptor = new DynamicTableNameInnerInterceptor();
    interceptor.setTableNameHandler(new TableShardHandler());
    interceptor.addInnerInterceptor(interceptor);
    return interceptor;
}

4.2 拦截层

java 复制代码
@Override
public String dynamicTableName(String sql, String tableName) {
    return tableShard(tableName);
}

public String tableShard(String tableName) {
    String suffix = DataShardStrategyHelper.getShardingTableSuffix();
    if (ObjectUtil.isNotEmpty(suffix)) {
        return tableName + "_" + suffix;
    }
    return tableName;
}

4.3 上下文传递层

java 复制代码
private static ThreadLocal<String> shardingTableSuffix = new ThreadLocal<>();

public static void setShardingTableSuffix(String suffix)   // 设置
public static String getShardingTableSuffix()               // 获取
public static void clearShardingTableSuffix()               // 清除

五、业务使用模式

java 复制代码
public List<XxxResponse> someMethod(String type) {
    try {
        if (StringUtils.isBlank(type)) {
            type = shardTableConfig.getWechatTableType();
        }
        setShardType(type);
        // 执行数据库操作...
    } finally {
        clearShardType();
    }
}

六、分表效果示例

type 参数 实际查询表
"wechat" t_product_wechat
"web" t_product_web
null t_product_wechat(默认)

七、设计特点

  1. 线程安全:基于 ThreadLocal,请求线程独立
  2. 侵入小:业务方法前后 set/clear,Mapper 层无感知
  3. 灵活路由:请求参数动态决定分表
  4. 防御性编程:finally 确保 ThreadLocal 清除
相关推荐
geovindu1 小时前
rust: Facade Pattern
开发语言·后端·设计模式·rust·外观模式
颜进强2 小时前
20 · NestJs循环依赖与 forwardRef:容器为什么在环面前会死,"占位再补齐"怎么救
前端·后端·ai编程
颜进强2 小时前
19 · NestJs @Global 落地账:装饰器与 `isGlobal` 参数,各在什么场景上岗
前端·后端·ai编程
她的男孩3 小时前
分片上传的大文件人人可下载:文件模块 isPrivate 在合并时被抹成 false,另有 4 个静默坑
java·后端·架构
颜进强3 小时前
18 · NestJS动态模块与 forRoot:`imports: [ConfigModule.forRoot({...})]` 到底在 import 什么
前端·后端·ai编程
xn71333 小时前
Personal AI Agent 架构实战:Memory、权限、跨 App 与本地/云端设计
人工智能·后端·agent
谢亮_vipxieliang3 小时前
Go defer、panic与recover核心知识点
开发语言·后端·golang
颜进强3 小时前
17 · 自定义 Provider 四形态:useValue / useClass / useFactory / useExisting 到底在选什么
前端·后端·ai编程
碎觉崽4 小时前
我的 QQ 机器人被腾讯反复踢下线,折腾了半个月才搞明白
后端
打工仔折腾 AI4 小时前
从零写一个CAD 05:以鼠标为中心的滚轮缩放矩阵顺序不能反
后端·python·线性代数·性能优化·矩阵·计算机外设·ai agent 实战