记录一次使用MP的TableNameHandler实现简单的分表需求

发布时间 2023-09-27 16:18:58作者: 紫叶&&

1.使用场景

有简单的分表需求,项目不允许嵌入其他分库分表框架

2.具体使用

2.1 TableNameHandler介绍

TableNameHandler是MP提供的一个动态表名处理接口,其原理是通过MP拓展的拦截器(DynamicTableNameInnerInterceptor)中动态修改解析完成后的sql中的表名。

2.2 具体使用

2.2.1 实现TableNameHandler接口

/**
 * 动态表名处理器
 * 使用完需要手动调用清除
 */
public class DynamicTableNameHolder implements TableNameHandler {

    private static final ThreadLocal<String> tableNameTL = ThreadLocal.withInitial(() -> StringUtil.EMPTY);

    private String getDynamicTableName(String tableName) {
        //如果有设置表名,则使用配置的表名
        if (StringUtil.isNotBlank(tableNameTL.get())) {
            return tableNameTL.get();
        } else {
            return tableName;
        }
    }

    @Override
    public String dynamicTableName(String sql, String tableName) {
        // 在这里根据业务逻辑决定要使用的表名
        String dynamicTableName = getDynamicTableName(tableName);
        return dynamicTableName;
    }

    public static void setTableName(String tableName) {
        tableNameTL.set(tableName);
    }

    public static void remove() {
        tableNameTL.remove();
    }
}

2.2.2 添加DynamicTableNameHolder 到拦截器

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
        HashMap<String, TableNameHandler> map = new HashMap<String, TableNameHandler>();

        //这里为不同的表设置对应表名处理器
        map.put("table_name", new DynamicTableNameHolder());

        dynamicTableNameInnerInterceptor.setTableNameHandlerMap(map);
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
        return interceptor;
    }

2.2.3配置对应的mapper与entity

@TableName("table_name")
public class Demo{
  ....
}
public interface JlinkDataMapper extends BaseMapper<Demo> {

}

2.2.3代码中使用

    public void getData() {
        try {
            //设置需要操作的表名
            DynamicTableNameHolder.setTableName("table_name2");
            //查询数据
            List<Demo> datas = demoMapper.selectList(null);
            //do something
        } finally {
            //需要手动清空
            DynamicTableNameHolder.remove();
        }
    }

在上面的代码中,demoMapper原本生成的sql里查询的表名是table_name,但经过DynamicTableNameHolder 处理,会被替换成table_name2,这样就简单实现了一个简单的分表需求。