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 清除
相关推荐
TechLee几秒前
一行代码防水平越权:用 PHP-Casbin 终结业务里的数据级 if-else
后端·php
步行cgn3 分钟前
Spring 底层如何创建对象:反射机制与实例化策略
java·后端·spring
Lyra_Infra4 分钟前
从 MySQL 到达梦:一次信创隔离环境里的数据库迁移踩坑实录
数据库·后端·mysql
程序员天天困6 分钟前
Kafka 接入 AI 的三条路线:MCP 提案、会话记忆与实时上下文
大数据·后端·kafka
明月_清风31 分钟前
用自然语言控制 Blender:开源项目 Blender MCP 深度介绍
人工智能·后端
JaguarJack1 小时前
Whim 是什么?一门把 PHP 被否决的设想真跑起来的实验语言
后端·php·服务端
明月_清风2 小时前
MHS:AI Agent 开始连接物理世界
人工智能·后端·网络协议
ssshooter2 小时前
Node.js 天生就是异步的,为什么还要消息队列?
javascript·后端·面试
福兮说2 小时前
Gin 项目里的错误处理:让 Controller 不必知道错误是怎么来的
后端·go·gin·架构设计
n8n2 小时前
Spring AI Alibaba Graph 实战:用图编排复杂业务,替代硬编码,支持分支、并行与人工确认
后端