Skip to content

fejay/mx-tableshard

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mx-tableshard

mx-tableshard 是一个基于 Spring Boot 3 + MyBatis / MyBatis-Plus 的轻量级分表组件。
组件通过 MyBatis 拦截器自动识别实体类上的 @TableShard 注解,从 SQL 参数中提取分片字段值,并将逻辑表名替换为实际物理表名。

功能特性

  • 支持 Spring Boot 自动装配。
  • 支持 MyBatis / MyBatis-Plus 查询和更新 SQL 拦截。
  • 支持实体类注解声明分表规则。
  • 内置三种分表策略:
    • HashShardStrategy:一致性 Hash 分表。
    • ModShardStrategy:取模分表。
    • DateShardStrategy:日期归档分表。
  • 支持从多种参数形态中提取分片值:
    • 普通实体对象。
    • Map 参数。
    • MyBatis ParamMap
    • MyBatis-Plus Wrapper
    • MyBatis ParameterMapping
    • SQL 条件中的 ? 占位符。
  • 日期分片支持按年、月、日、季度生成表名后缀。
  • SQL 分片字段条件支持:
    • =
    • IN (...)
    • LIKE ?
    • >
    • <
    • >=
    • <=

环境要求

  • JDK 21+
  • Spring Boot 3.x
  • MyBatis Spring Boot Starter 3.x
  • MyBatis-Plus 3.5.x(可选,使用 MyBatis-Plus 时需要)

安装使用

当前项目版本:

<groupId>com.mx</groupId>
<artifactId>mx-tableshard</artifactId>
<version>1.0-SNAPSHOT</version>

如果在本地项目中使用,先安装到本地 Maven 仓库:

mvn clean install

业务项目中引入依赖:

<dependency>
    <groupId>com.mx</groupId>
    <artifactId>mx-tableshard</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

配置说明

组件默认启用。

shendu:
  shard:
    enabled: true

如需关闭分表组件:

shendu:
  shard:
    enabled: false

自动装配入口:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

快速开始

1. 准备物理表

以订单表为例,逻辑表名为 t_order,按月份进行日期分表:

CREATE TABLE t_order_202406 (
    id BIGINT PRIMARY KEY,
    order_no VARCHAR(64),
    user_id BIGINT,
    create_time DATETIME
);

CREATE TABLE t_order_202407 (
    id BIGINT PRIMARY KEY,
    order_no VARCHAR(64),
    user_id BIGINT,
    create_time DATETIME
);

业务 SQL 中仍然写逻辑表名:

SELECT * FROM t_order WHERE create_time >= ?

组件会在执行前替换为:

SELECT * FROM t_order_202406 WHERE create_time >= ?

2. 在实体类上声明分表规则

import com.baomidou.mybatisplus.annotation.TableName;
import annotation.org.wf.mx.tableshard.TableShard;
import strategy.org.wf.mx.tableshard.DateShardStrategy;

import java.time.LocalDateTime;

@TableName("t_order")
@TableShard(tableName = "t_order", shardColumn = "create_time", strategy = DateShardStrategy.class,
    shardPattern = "yyyyMM")
public class Order {

    private Long id;

    private String orderNo;

    private Long userId;

    private LocalDateTime createTime;

    // getter / setter
}

3. 编写 Mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface OrderMapper extends BaseMapper<Order> {
}

正常使用 MyBatis / MyBatis-Plus 查询即可:

LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(Order::getCreateTime, LocalDateTime.of(2024, 6, 1, 0, 0));

List<Order> orders = orderMapper.selectList(wrapper);

createTime = 2024-06-01T00:00,则会路由到:

t_order_202406

@TableShard 注解说明

@TableShard(
        tableName = "t_order",
        shardNum = 4,
        shardColumn = "order_no",
        strategy = HashShardStrategy.class,
        shardPattern = ""
)
属性 说明 必填 默认值
tableName 逻辑表名。为空时尝试从 @TableName 或 MyBatis-Plus 表信息中获取。 ""
shardNum 分表数量。Hash / Mod 策略需要配置。 0
shardColumn 分片字段名,支持驼峰和下划线匹配。
strategy 分表策略类。 HashShardStrategy.class
shardPattern 日期分片格式,主要用于 DateShardStrategy ""

内置分表策略

一致性 Hash 分表

适合订单号、用户 ID 等希望分布相对均匀的字段。

@TableShard(
        tableName = "t_order",
        shardNum = 4,
        shardColumn = "order_no",
        strategy = HashShardStrategy.class
)
public class Order {
}

表名示例:

t_order_1
t_order_2
t_order_3
t_order_4

取模分表

适合分片数量固定、分片键分布相对均匀的场景。

@TableShard(
        tableName = "t_user",
        shardNum = 8,
        shardColumn = "user_id",
        strategy = ModShardStrategy.class
)
public class User {
}

表名示例:

t_user_1
t_user_2
...
t_user_8

日期归档分表

适合日志、订单、流水等按时间归档的数据。

@TableShard(
        tableName = "t_log",
        shardColumn = "create_time",
        strategy = DateShardStrategy.class,
        shardPattern = "yyyyMM"
)
public class LogRecord {
}

支持的 shardPattern

模式 说明 示例日期 物理表名
yyyy 按年分表 2024-06-15 t_log_2024
yyyyMM 按月分表 2024-06-15 t_log_202406
yyyyMMdd 按日分表 2024-06-15 t_log_20240615
yyyyQ 按季度分表 2024-05-15 t_log_2024q2

日期分片值支持:

  • LocalDateTime
  • LocalDate
  • java.util.Date
  • 毫秒时间戳 Long
  • 日期字符串,例如:
    • 2024-06-15
    • 2024-06-15 10:30:00
    • 2024-06-15T10:30:00

SQL 条件支持

分片字段可以出现在以下条件中:

WHERE order_no = ?
WHERE order_no IN (?)
WHERE create_time > ?
WHERE create_time >= ?
WHERE create_time < ?
WHERE create_time <= ?
WHERE create_time >= #{startTime}
WHERE create_time <= #{endTime}

日期分片示例:

SELECT * FROM t_order WHERE status = ? AND create_time >= ?

参数:

status = 1
create_time = 2024-06-01T00:00

shardPattern = "yyyyMM" 时路由到:

t_order_202406

重要限制

1. 当前是单表路由,不是多表路由

组件当前会根据提取到的一个分片值计算一个物理表名。

例如:

WHERE create_time >= '2024-06-30'
  AND create_time < '2024-07-02'

如果按月分表,真实数据可能分布在:

t_order_202406
t_order_202407

当前组件不会自动生成 UNION ALL,也不会自动查询多个物理表。此类跨分片范围查询需要业务方自行拆分,或在后续版本中支持多表路由。

2. SQL 解析基于规则匹配

当前组件没有引入完整 SQL Parser,分片字段定位主要基于 SQL 字符串规则匹配。复杂 SQL 场景需谨慎验证,例如:

WHERE DATE(create_time) >= ?
WHERE ? <= create_time
WHERE EXISTS (SELECT 1 FROM ...)

自定义分表策略

实现 ShardStrategy 接口:

import strategy.org.wf.mx.tableshard.ShardStrategy;
import org.springframework.stereotype.Component;

@Component
public class TenantShardStrategy implements ShardStrategy {

    @Override
    public String computeTableName(String logicTableName, int shardNum, String shardKey) {
        int index = Math.abs(shardKey.hashCode()) % shardNum + 1;
        return logicTableName + "_" + index;
    }
}

实体类中使用自定义策略:

@TableShard(
        tableName = "t_tenant_order",
        shardNum = 16,
        shardColumn = "tenant_id",
        strategy = TenantShardStrategy.class
)
public class TenantOrder {
}

自定义策略注册为 Spring Bean 后,组件会通过 ShardStrategyRegistry 自动发现并使用。

测试与 Demo

运行全部测试:

mvn test

运行日期分片比较操作符 Demo:

mvn -Dtest=DateShardComparisonDemoTest test

Demo 文件:

src/test/java/com/mx/tableshard/demo/DateShardComparisonDemoTest.java

运行 SQL 参数定位测试:

mvn -Dtest=ShardSqlParameterLocatorTest test

测试文件:

src/test/java/com/mx/tableshard/extractor/ShardSqlParameterLocatorTest.java

项目结构

src/main/java/com/mx/tableshard
├── annotation      # @TableShard 注解
├── config          # Spring Boot 自动配置与配置属性
├── extractor       # 分片值提取链路
├── interceptor     # MyBatis 分表拦截器
├── strategy        # 分表策略
└── utils           # 工具类

工作原理

核心执行流程:

MyBatis 执行 SQL
        ↓
ShardTableInterceptor 拦截
        ↓
解析 Mapper 对应实体类上的 @TableShard
        ↓
ShardValueExtractor 提取分片字段值
        ↓
ShardStrategy 计算物理表名
        ↓
替换 SQL 中的逻辑表名
        ↓
继续执行替换后的 SQL

示例:

SELECT * FROM t_order WHERE create_time >= ?

替换后:

SELECT * FROM t_order_202406 WHERE create_time >= ?

About

一个基于 Spring Boot 3 + MyBatis / MyBatis-Plus 的轻量级分表组件

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages