Mybatis-Plus版本:3.4.3.4
需求:在数据库中存在多个表结构相同,表名不同数据表 , 现需根据条件判断并选择操作哪一个数据表。在不使用动态表明的情况下, 一个表对应一个实体类,实体类又需要对应不同的Mapper、Service,明显增加了很多代码量。如果使用动态表名的方式,则只需要一个实体类就可以操作多张表,减少工作量,提升效率。
假设存在两个数据表(有些什么字段不重要,只要两个表字段相同就行):data_01、data_60
已知两个表字段相同, 假设有一个id(Long),一个data(String), 然后随便造几条数据。
我们先在写好实体类并指定好表名的相同部分(不指定也行,Mybatis-plus会自动解析实体类的名字):
@Data
@TableName(value = "data")
public class Data {
    @TableId(type = IdType.AUTO)
    private Long id;
    
    private String data;
}随后编写对应的Mapper类
@Mapper
public interface DataMapper extend BaseMapper<Data> {
}再编写RequestDataHelper工具类(这个类用于操作一个只有当前线程能访问到的对象,来自于MybatisPlus官方示例代码):
public class RequestDataHelper {
    /**
     * 请求参数存取
     */
    private static final ThreadLocal<Map<String, Object>> REQUEST_DATA = new ThreadLocal<>();
    /**
     * 设置请求参数
     *
     * @param requestData 请求参数 MAP 对象
     */
    public static void setRequestData(Map<String, Object> requestData) {
        REQUEST_DATA.set(requestData);
    }
    /**
     * 获取请求参数
     *
     * @param param 请求参数
     * @return 请求参数 MAP 对象
     */
    public static <T> T getRequestData(String param) {
        Map<String, Object> dataMap = getRequestData();
        if (CollectionUtils.isNotEmpty(dataMap)) {
            return (T) dataMap.get(param);
        }
        return null;
    }
    /**
     * 获取请求参数
     *
     * @return 请求参数 MAP 对象
     */
    public static Map<String, Object> getRequestData() {
        return REQUEST_DATA.get();
    }
}这个类中使用到了一个叫做ThreadLocal的类,这个类维护了一个只有当前线程能访问到的对象, 此处我们用来存取一个Map。
最后我们编写MybatisPlus的配置类:
@Configuration
public class MybatisPlusConfig {
    
     @Bean
     public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 动态表名拦截器
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
        dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
            // 获取参数方法
            Map<String, Object> paramMap = RequestDataHelper.getRequestData();
            String rate = (String) paramMap.get("rate");
            return tableName + "_" + rate;
        });
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
        return interceptor;
    }
    
}可以看到其中使用 DynamicTableNameInnerInterceptor 类创建了一个动态表名拦截器, 随后调用setTableNameHandler 方法设置一个表名处理器 TableNameHandler,TableNameHandler 是一个interface接口,返回值是最终的表名,这里直接使用了lambda表达式来实现了这个接口。可以看到这里调用了RequestDataHelper.getRequestData() 这个方法去获取到了一个Map, 这个map就是我们用ThreadLocal维护的那个map,这个接口的实现就是根据map中我们设置的字段来拼接一个新的表名并返回。
测试,编写一个测试方法, 测试从data_01中查询数据:
@Test
public void test(){
    
    @Autowired
    private DataMapper dataMapper;
    
    RequestDataHelper.setRequestData(new HashMap<>() {{
            put("rate", "01");
        }});
    dataMapper.selectList(new QueryWrapper<>());
}最终,测试通过,可以得到正确的数据。整个流程也就是在执行增删改查之前使用RequestDataHelper.setRequestData 来设置一个参数, 然后根据RequestDataHelper.getRequestData这个方法来获取到这个参数拼接出最后的表名。


感谢分享!
您好~我是腾讯云+社区的运营,关注了您分享的技术文章,觉得内容很棒,我们诚挚邀请您加入腾讯云自媒体分享计划。完整福利和申请地址请见:https://cloud.tencent.com/developer/support-plan
作者申请此计划后将作者的文章进行搬迁同步到社区的专栏下,你只需要简单填写一下表单申请即可,我们会给作者提供包括流量、云服务器等,另外还有些周边礼物。
我们诚挚的邀请您并期待您的加入~