基于Mybatis-Plus实现动态切换表名

本文介绍了如何在Mybatis-Plus中使用动态表名拦截器,实现在单个Mapper和PO类下处理多个结构相同的表,通过手动或自动策略切换表名,提高代码复用性和扩展性,同时提到的遗留问题是拦截器无法获取预编译SQL的参数。
摘要由CSDN通过智能技术生成

一、背景

先抛出一个问题,我们项目是基于mybatis-plus做Dao层开发,我现在有两个表结构相同的表table1和table2,如何对这两个表做操作呢,写两个Mapper和两个xxxPO?这显然不够优雅,但是如果我们的Mapper中有很多自定义的逻辑和方法或者table表不是两个而是10个呢,那么显然重复写Mapper和xxxPO不符合复用性和可扩展性,那么在Mybatis-Plus中如何使用一个Mapper和xxxPO查询多个表结构相同的表,这里可以借助MybatisPlus的动态表名拦截器。

二、实现过程

1.需求

存在3个表结构相同的表t_user1、t_user2、t_user3,我想通过一套Mapper及PO实现对这三个表的手动或以某种策略的增删改查。

2.环境准备

以mysql数据库为例,建表语句如下:

CREATE TABLE `t_user1` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

对应的Mapper为UserMapper。

package com.fkp.dynamic_table_name.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fkp.dynamic_table_name.entity.User;

/**
 * @author fkp
 */
public interface UserMapper extends BaseMapper<User> {
}

对应的实体类为User。注意这里的@TableName("t_user")是t_user不是具体的哪个表名。

package com.fkp.dynamic_table_name.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * @author fkp
 */
@TableName("t_user")
@Data
public class User {
    @TableId
    private Integer id;
    private String name;
    private Integer age;

}

3.实现动态表名切换

①手动切换

借助ThreadLocal,执行查询前设置ThreadLocal中的值来决定查哪个表。

定义手动切换的工具类

package com.fkp.dynamic_table_name.utils;

/**
 * @author fengkunpeng
 * @version 1.0
 * @description
 * @date 2023/9/20 15:56
 */
public class DynamicTableNameUtils {

    //t_user -> t_user1 - t_user3
    private static final ThreadLocal<Integer> DYNAMIC_TABLE_T_USER = new ThreadLocal<>();

    public static void applyTable(int index){
        DYNAMIC_TABLE_T_USER.set(index);
    }

    public static void releaseCurrTableName(){
        //默认访问t_user1
        DYNAMIC_TABLE_T_USER.set(1);
    }

    public static String getCurrTableName(){
        return "t_user" + DYNAMIC_TABLE_T_USER.get();
    }
}

实现MybatisPlus动态表明拦截器,实现逻辑。

package com.fkp.dynamic_table_name.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.fkp.dynamic_table_name.constant.CommonConstants;
import com.fkp.dynamic_table_name.utils.DynamicTableNameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Optional;

/**
 * @author fengkunpeng
 * @version 1.0
 * @description
 * @date 2023/9/20 15:41
 */
@Configuration(proxyBeanMethods = false)
public class MybatisPlusConfig {

    //拦截器,获取到表名给替换
    @Bean
    public MybatisPlusInterceptor dynamicTableNameInnerInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
        dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
            //若操作的表是t_user表,则从ThreadLocal中取表名t_user1 - t_user3,默认t_user1
            if(StringUtils.equalsIgnoreCase(CommonConstants.TABLE_KEY_OBJECT, tableName)){
                tableName = DynamicTableNameUtils.getCurrTableName();
                //执行完本次操作后还原标志位,避免在后续操作中影响对原来表的正常操作
                DynamicTableNameUtils.releaseCurrTableName();
            }
            return tableName;
            //这里也可以采用某种策略切换表名,例如t_user(id%3 + 1)
        });
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
        return interceptor;
    }
}

②自动切换

使用某种策略决定对哪个表操作,例如id%3 + 1为表的后缀。

实现过程参考手动切换场景,只不过不需要ThreadLocal的工具类,直接在拦截器中书写相关逻辑即可。

遗留问题

在拦截器中无法取到预编译sql对应的参数。后续解决。

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MyBatis-Plus是一个基于MyBatis的增强工具,它提供了许多方便的功能,其中包括动态表名的支持。通过使用MyBatis-Plus提供的DynamicTableNameInnerInterceptor拦截器,可以在运行时动态替换SQL语句中的表名。 使用MyBatis-Plus实现动态表名有以下几个作用: 1. 实现数据分表或数据分区:可以根据特定的规则生成动态表名,例如按照时间分表或按照业务冷热数据分离后将数据存储在不同的表中。 2. 隐藏数据表名:在某些情况下,为了安全或其他目的,可能需要隐藏数据库的表名。使用DynamicTableNameInnerInterceptor可以将表名进行动态替换,从而达到隐藏表名的效果。 3. 提高系统的可扩展性:通过动态表名解析器,可以将不同的数据表或数据库实例进行解耦,从而提高系统的可扩展性。例如,可以将一个大型的数据库系统分成多个小型的数据库实例,然后通过动态表名解析器将SQL语句分发到不同的实例中。 4. 简化代码开发:使用DynamicTableNameInnerInterceptor,可以避免在代码中硬编码SQL语句中的表名,从而简化代码的开发和维护。特别是在应对表结构频繁变化的场景下,使用该拦截器能够更快速地实现表名变更,从而降低维护成本。 因此,通过使用MyBatis-Plus的DynamicTableNameInnerInterceptor拦截器,可以实现mybatis-plus动态表名的功能,并带来诸多好处。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【mybatis-plus系列】动态表名](https://blog.csdn.net/qyj19920704/article/details/130010294)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [mybatis-plus动态表名实现](https://blog.csdn.net/zhangsuhua0702/article/details/122807303)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值