SpringBoot - MyBatis-Plus使用详解21(动态表名)
二十一、动态表名
1,业务场景
(1)有时我们希望存储或读取数据的时候能够根据情况、或根据传入参数来动态的选择对应的表。比如我们数据库里的用户信息表通过年份拆分(使用年份做后缀):

@Data public class UserInfo { private Integer id; private String userName; private String passWord; private Integer age; }
2,样例代码
(1)首先我们实现 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; } }
(2)然后开始查询数据:
@RestController public class HelloController { @Autowired UserInfoMapper userInfoMapper; @GetMapping("/test") public List<UserInfo> test() { return userInfoMapper.selectList(null); } }
(3)查看控制台日志可以发现实际查询的是 user_info_2020 这张表:

附:根据参数来动态选择对应的表
(1)这里我们对动态表名解析器代码稍作修改,根据传入的参数 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; } } }
(2)修改 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); }
(3)我们调用这个 Mapper 查询时传入一个指定年份,比如 2019:
@RestController public class HelloController { @Autowired UserInfoMapper userInfoMapper; @GetMapping("/test") public List<UserInfo> test() { return userInfoMapper.getAll(2019); } }
(4)查看控制台日志可以发现实际查询的是 user_info_2019 这张表:
