动态表名
1、业务场景
- 有时我们希望存储或读取数据的时候能够根据情况、或根据传入参数来动态的选择对应的表。比如我们数据库里的用户信息表通过年份拆分(使用年份做后缀)
- 而对应的实体类是不包含年份后缀的:
@Data
public class UserInfo {
private Integer id;
private String userName;
private String passWord;
private Integer age;
}
2、样例代码
- 首先我们实现 ITableNameHandler 接口注入到 DynamicTableNameParser 处理器链中,将动态表名解析器注入到 MP 解析链(这里我们获取当前年份作为 user_info 表后缀)。
提示:动态表名的原理就是解析替换设定表名为处理器的返回表名
@Configuration
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
DynamicTableNameParser dynamicTableNameParser = new DynamicTableNameParser();
dynamicTableNameParser.setTableNameHandlerMap(new HashMap<String, ITableNameHandler>(2) {{
put("user_info", (metaObject, sql, tableName) -> {
// metaObject 可以获取传入参数,这里实现你自己的动态规则
// 这里我使用当前年份做后缀
int year = Calendar.getInstance().get(Calendar.YEAR);
return tableName + "_" + year;
});
}});
paginationInterceptor.setSqlParserList(Collections.singletonList(dynamicTableNameParser));
return paginationInterceptor;
}
}
- 然后开始查询数据:
@RestController
public class HelloController {
@Autowired
UserInfoMapper userInfoMapper;
@GetMapping("/test")
public List<UserInfo> test() {
return userInfoMapper.selectList(null);
}
}
- 查看控制台日志可以发现实际查询的是 user_info_2020 这张表:
3、根据参数来动态选择对应的表
- 这里我们对动态表名解析器代码稍作修改,根据传入的参数 year 来动态决定使用的数据表:
- 比如当 year 参数为 2019 则使用 user_info_2019 这张表。
- 如果没有 year 参数则使用当前年份做后缀,比如 user_info_2020
@Configuration
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
DynamicTableNameParser dynamicTableNameParser = new DynamicTableNameParser();
dynamicTableNameParser.setTableNameHandlerMap(new HashMap<String, ITableNameHandler>(2) {{
put("user_info", (metaObject, sql, tableName) -> {
// 获取传入参数 year,如果有的话做为后缀,没有的话则使用当前年份作为后缀
Object param = getParamValue("year", metaObject);
String year = param !=null ? String.valueOf(param)
: String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
return tableName + "_" + year;
});
}});
paginationInterceptor.setSqlParserList(Collections.singletonList(dynamicTableNameParser));
return paginationInterceptor;
}
/**
* 获取参数值
*/
private Object getParamValue(String title, MetaObject metaObject){
//获取参数
Object originalObject = metaObject.getOriginalObject();
JSONObject originalObjectJSON = JSON.parseObject(JSON.toJSONString(originalObject));
JSONObject boundSql = originalObjectJSON.getJSONObject("boundSql");
try {
JSONObject parameterObject = boundSql.getJSONObject("parameterObject");
return parameterObject.get(title);
}catch (Exception e) {
return null;
}
}
}
- 修改 UserInfoMapper 接口,在定义方法中添加 year 参数:
注意:如果方法只有一个参数必须添加 @Param 注解,否则动态表名解析器中无法通过参数名获取对应的值。
public interface UserInfoMapper extends BaseMapper<UserInfo> {
@Select("select * from user_info")
List<UserInfo> getAll(@Param("year") int year);
}
- 如果方法有多个参数的话,可以不用添加 @Param 注解:
public interface UserInfoMapper extends BaseMapper<UserInfo> {
@Select("select * from user_info")
List<UserInfo> getAll(int year, int month);
}
- 我们调用这个 Mapper 查询时传入一个指定年份,比如 2019:
@RestController
public class HelloController {
@Autowired
UserInfoMapper userInfoMapper;
@GetMapping("/test")
public List<UserInfo> test() {
return userInfoMapper.getAll(2019);
}
}
- 查看控制台日志可以发现实际查询的是 user_info_2019 这张表:
--------------最后感谢大家的阅读,愿大家技术越来越流弊!--------------
--------------也希望大家给我点支持,谢谢各位大佬了!!!--------------