使用Mybatis-Plus 动态表名 SQL 解析器实现MySQL分表

前言

随着业务发展,数据库单表量将会持续增长,当增长到一定大小,是需要对应的处理以解决数据查询越来越慢的问题的。
一般的扩展方案分为两种,一种是垂直扩展,即增大单机的配置。 另一种则是水平扩展,是将任务分配到多台计算机上。

我们的应用系统使用的是SpringBoot+Mybatis-Plus的搭配,由于分表业务比较简单,就没有使用插件,而是使用Mybatis-Plus提供的 DynamicTableNameParser 处理器直接在程序中做动态路由。
由于官方文档在此处描述的并不是特别详细,所以写这篇博客作为记录。

开发

分表策略就不在此做说明了,网上已经有非常多不同的处理方式了,在这里主要阐述怎么样使用Mybatis-Plus提供的 ITableNameHandler 接口将不同表的做出不同处理。

实现 ITableNameHandler 接口

首先我们需要实现 ITableNameHandler 接口,该接口有两个方法(process, dynamicTableName),process()方法是做表名SQL处理的,该方法有默认实现,它依赖于dynamicTableName()方法,所以我们需要重写的方法便是dynamicTableName()方法
dynamicTableName()方法有三个入参,metaObject包括了元数据对象,sql是我们即将要执行的SQL,tableName则是我们执行的SQL表名称。我们需要修改的便是tableName。
下方我的代码逻辑是从DaysContext上下文对象中拿到事先设置的表名动态规则生成的表后缀,拼接上tableName便是我们需要动态路由的表名称了。

@Component
public class MyDynamicTableNameParser implements ITableNameHandler {

    @Override
    public String dynamicTableName(MetaObject metaObject, String sql, String tableName) {

        DaysContext.Days days = DaysContext.get();

        // 加上分表逻辑后缀
        return tableName + "_" + days.getTableSuffix();
    }
}

将配置注入到Mybatis-Plus配置中

接下来需要将我们的动态表名处理器 MyDynamicTableNameParser 配置到 PaginationInterceptor 对象中

@Configuration
public class MybatisPlusConfig {

    private final MyDynamicTableNameParser myDynamicTableNameParser;

    public MybatisPlusConfig(MyDynamicTableNameParser myDynamicTableNameParser) {
        this.myDynamicTableNameParser = myDynamicTableNameParser;
    }

    /**
     * 分页, 分表插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptorMysql() {

        // 分页
        PaginationInterceptor page = new PaginationInterceptor();
        page.setDialectType("mysql");

        // 分表
        dynamicTableNameParser(page);

        return page;
    }

    /**
     * 分表
     */
    private void dynamicTableNameParser(PaginationInterceptor page) {

        // 为指定表设置动态表名处理器
        HashMap<String, ITableNameHandler> map = new HashMap<>(2);
        map.put("sys_user", myDynamicTableNameParser);
        map.put("sys_logs", myDynamicTableNameParser);

        // 将需要处理的表添加到动态表名 SQL 解析器
        DynamicTableNameParser dynamicTableNameParser = new DynamicTableNameParser();
        dynamicTableNameParser.setTableNameHandlerMap(map);

        // 加入处理器链中
        List<ISqlParser> iSqlParsers = new ArrayList<>();
        iSqlParsers.add(dynamicTableNameParser);
        page.setSqlParserList(iSqlParsers);
    }
}

在dynamicTableNameParser()方法中,第一个代码块将需要动态路由的表通过K-V的形式配置我们刚编写的路由处理器对象。
第二个代码块中将我们添加的表名处理器设置到 Mybatis-Plus的 表名处理器 DynamicTableNameParser 中
第三个代码块将我们配置的表名处理器添加到Mybatis-Plus的处理器链中
通过上面的配置,我们就能够根据配置的路由规则,将配置的需要路由的表动态拼接上我们生成的后缀名了。

总结

框架做了很好的封装,整个过程还是非常顺利的,也顺利通过了测试。写这篇博客做个记录。