随着业务数据量的不断增长,你是否还在为传统的、侵入性强的分表方案而烦恼?复杂的手写 SQL 拼接、繁琐的拦截器改造,以及随之而来的高昂维护与测试成本,都是需要面对的挑战。本文介绍一个聚焦于“简单、稳定、可扩展”的 MyBatis-Plus 动态表名分表解决方案。
该项目是一个开源的 Starter,旨在通过“注解 + 配置”的方式,将分表操作的复杂度降到最低,实现开箱即用、零业务代码侵入。你可以轻松地将分表逻辑收敛到配置和几个简单的注解中,像编写普通 CRUD 一样处理分表业务。
为什么需要动态表名?
在处理海量数据的业务场景中,按时间(如年/月/日)或按用户等维度进行数据分片已成为常态。然而,传统实现往往涉及底层 SQL 改写、框架拦截器改造、策略维护与回归测试等多个环节,不仅成本高,还容易出错。这个 MyBatis-Plus 动态表名 Starter 旨在解决这些问题,它能够帮助你:
- 开箱即用,对业务代码零侵入。
- 通过注解驱动,让你编写分表业务如同编写普通 CRUD 一样简单。
- 基于策略模式,扩展自定义分表逻辑更加顺畅。
- 提供完整的日志支持,方便进行故障定位。

核心特性一览
- 开箱即用:自动装配,默认启用。
- 日期分表:支持按年、按月、按日等多种时间粒度一键切换。
- 哈希分表:根据指定哈希键的值进行均匀分片。
- 注解驱动:使用
@DateSharding、@HashSharding 等注解即可完成分表路由。
- 工具类支持:通过
DynamicTableUtils 可以灵活包裹任意代码块。
- 灵活优先级:支持多策略并存,且执行优先级可控。
- 完整日志:详细记录策略匹配与表名替换过程,便于调试。
如何安装?
Maven 依赖:
<dependency>
<groupId>com.lizhuolun</groupId>
<artifactId>mybatis-plus-dynamic-table-starter</artifactId>
<version>1.0.0</version>
</dependency>
Gradle 依赖:
implementation 'com.lizhuolun:mybatis-plus-dynamic-table-starter:1.0.0'
运行环境要求:Java 21+,Spring Boot 3.5.6+,MyBatis-Plus 3.5.14+。
快速上手(三步到位)
- 添加依赖:确保你的项目中已引入 Spring Web 与 MyBatis-Plus Starter。
- 配置分表策略:在
application.yml 中启用并配置策略。
# 动态表名配置
dynamic-table:
enabled: true
enable-sql-log: true
# 日期分表:订单与日志按月/按日分表
date-sharding:
- tables: [t_order, t_log]
date-pattern: "yyyyMM"
priority: 1
- tables: [t_access_log]
date-pattern: "yyyyMMdd"
priority: 2
# 哈希分表:用户相关表分8张
hash-sharding:
- tables: [t_user, t_user_profile]
table-count: 8
priority: 10
-
编写代码:支持注解或工具类两种方式,任选其一即可。
注解方式(推荐):
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
// 自动根据日期分表(如 t_order_202501)
@DateSharding(value = "t_order", dateParam = "date")
public Order create(Order order, LocalDate date) {
orderMapper.insert(order);
return order;
}
}
工具类方式(灵活包裹任意代码块):
public List<Order> queryByDate(LocalDate date) {
return DynamicTableUtils.executeWithDate("t_order", date, () -> {
return orderMapper.selectList(null);
});
}
进阶用法探索
多表同时路由:
一次性为多个逻辑表指定实际分表名,确保批量操作在同一个分表上下文中进行。
Map<String, String> tableMap = Map.of(
"t_order", "t_order_202501",
"t_log", "t_log_202501"
);
DynamicTableUtils.executeWithTables(tableMap, () -> {
orderMapper.insert(order);
logMapper.insert(log);
});
自定义策略:
如果你有更特殊的分表规则,可以实现 TableRouterStrategy 接口,轻松接入你的自定义路由逻辑。
@Component
public class CustomTableRouterStrategy implements TableRouterStrategy {
@Override
public boolean match(String logicTableName) { return “t_custom”.equals(logicTableName); }
@Override
public String getActualTableName(String logic, Object ctx) { return logic + “_” + suffix(ctx); }
@Override
public String getStrategyName() { return “CustomTableRouterStrategy”; }
@Override
public int getPriority() { return 100; }
}
调试技巧与性能建议
开启日志定位:
在开发或排查问题时,开启 SQL 日志可以清晰看到表名替换的过程。
dynamic-table:
enable-sql-log: true
logging:
level:
com.lizhuolun.mybatis.dynamic: DEBUG
推荐数据库连接池配置:
对于分表场景,合理的连接池配置有助于提升性能和稳定性,这也是现代 Java 后端应用的常见优化点。
spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
常见问题 (FAQ)
- 表名未替换:检查目标表是否在配置的
tables 列表中、策略是否匹配成功,并查看启动的调试日志。
- 策略不生效:确认注解参数(如
dateParam / hashKey)是否与方法入参对应,并确保 Spring AOP 正常工作。
- SQL 执行异常:首先核验数据库中对应的实际分表是否存在、表结构是否一致;然后查看日志中打印的最终替换后的 SQL。
适用场景与优势对比
- 业务数据归档:如订单、日志等随时间快速增长的数据,按月或按日分表可以大幅提升归档和查询效率。
- 用户维度分片:根据用户ID等维度分散数据,能有效缓解热点写入与读取的压力。
- 与传统方案对比:相比于手写拦截器,本方案更加轻量、配置化、易于扩展;通过注解即用的方式,显著降低了后期维护成本。
快速验证与项目资源
- 演示项目 (Demo):你可以访问项目仓库中的
mybatis-plus-dynamic-table-demo,按照 README 初始化数据库并运行 mvn spring-boot:run 来快速体验。
- 项目仓库:
通过简单的配置和注解,这个 Starter 让 数据库 分表不再是一项繁琐的工程。如果你正在寻找一种优雅、低侵入的方式来处理 MyBatis-Plus 下的分表需求,不妨尝试一下这个 开源实战 项目。也欢迎在 云栈社区 与更多开发者交流分库分表及其他后端架构经验。