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
作者申请此计划后将作者的文章进行搬迁同步到社区的专栏下,你只需要简单填写一下表单申请即可,我们会给作者提供包括流量、云服务器等,另外还有些周边礼物。
我们诚挚的邀请您并期待您的加入~