MybatisPlus动态修改表名或增加库名

背景

在数据库操作过程中,经常有修改表名的需求,例如:分表时,修改表名加上分表前后缀;多数据库一个实例,表名前面加上库名,实现本地跨库事务等等。
我用到的场景是后者,动态加库名。由于使用了MybatisPlus,整个开发过程中不会自己写sql,也没办法通过硬编码修改表名。

解决方案

MybatisPlus中只需要一个配置类即可自定义,动态修改表名,代码如下:

@Configuration
public class MybatisPlusConfig {
    List<String> tables = Lists.newArrayList("user","class");
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        DynamicTableNameParser dynamicTableNameParser = new DynamicTableNameParser();
        dynamicTableNameParser.setTableNameHandlerMap(new HashMap<String, ITableNameHandler>() {{
            tables.forEach(tableTitle -> put(tableTitle,(metaObject, sql, tableName) -> "db01." + tableName ));
        }});
        paginationInterceptor.setSqlParserList(Collections.singletonList(dynamicTableNameParser));
        return paginationInterceptor;
    }
}

代码说明:
两个核心类:DynamicTableNameParser 动态解析表名,ITableNameHandler 表名处理。
DynamicTableNameParser会根据当前sql的tableName获取对应的ITableNameHandler,上面用拉姆达表达式,实现了ITableNameHandler中的dynamicTableName方法,拼上前缀。
ITableNameHandler源码如下:


    /**
     * 表名 SQL 处理
     *
     * @param metaObject 元对象
     * @param sql        当前执行 SQL
     * @param tableName  表名
     * @return
     */
    default String process(MetaObject metaObject, String sql, String tableName) {
        String dynamicTableName = dynamicTableName(metaObject, sql, tableName);
        if (null != dynamicTableName && !dynamicTableName.equalsIgnoreCase(tableName)) {
            // 直接替换字符串对于 SQL 操作是不那么好做,这里修复只能尽可能的保证处理没问题
            String regex = "(?<=\\s)\\Q" + tableName + "\\E(?=\\s)";
            return sql.replaceAll(regex, dynamicTableName);
        }
        return sql;
    }

    /**
     * 生成动态表名,无改变返回 NULL
     *
     * @param metaObject 元对象
     * @param sql        当前执行 SQL
     * @param tableName  表名
     * @return String
     */
    String dynamicTableName(MetaObject metaObject, String sql, String tableName);

进一步优化方案

这里的方案,哪些表需要重写表名,需要硬编码到代码中,自定义表名列表。如何做成自动的呢?
1. 将需要使用不同表的mapper接口,分目录存放。
2. 自定义的tableNameHandlerMap,保存为静态对象,随时可以修改。
3. 在mybatis的Interceptor中,根据当前sql的目录路径和表名,动态设置tableNameHandlerMap。
目前项目只用到了几张表,优化方案,暂未提供代码例子。有更好方案,欢迎评论区交流,谢谢。


版权声明:本文为zjy_love_java原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。