业务场景
MySQL中需要对一条数据中某个字段做特殊的扩展处理,比如:为用户设置某些特定的标签(标签包含排序、代码、名字)
方案对比
多字段存储(不推荐)
在主表中新增tag_sort、tage_code、tag_name,多个标签使用特殊字符分割且存储顺序需要一一对应,示例:
tag_sort=1,2,3
tage_code=tall,rich,cool
tag_name=高,富,帅
子表(推荐)
新建tag表,存储关联用户的id、排序、代码、名字。
扩展字段使用json类型存储(推荐)
直接使用tag字段存储json数据,示例:
tag=[
{"tag_sort":1,"tage_code":"tall","tag_name":"高"},
{"tag_sort":2,"tage_code":"rich","tag_name":"富"},
{"tag_sort":3,"tage_code":"cool","tag_name":"帅"}
]
准备工作
MySQL 版本 >= 8.0
-- 新建测试表
CREATE TABLE `demo`.`user`  (
  `id` bigint(32) NOT NULL COMMENT '主键id',
  `name` varchar(50) NULL COMMENT '名称',
  `tag` json NULL COMMENT '标签',
  PRIMARY KEY (`id`)
);
案例
使用扩展字段方式
版本
mybatis 3.5.1
mybatis-plus 3.5.2
示例代码
查询所有包含高、富、帅三个标签的用户
SQL实现
SELECT u.*
FROM user u,
JSON_TABLE(
    u.tag,
    '$[*]' 
    COLUMNS(
        tag_code VARCHAR(255) PATH '$.tag_code',
        tag_sort_no INT PATH '$.tag_sort_no'
    )
) AS u
WHERE u.tag_code IN (1, 2, 3)
order by id
mybatis-plus实现
       // 代码示例
       List<String> tagCodes = dto.getTagCodes();
        List<UserEntity> existConfigs = new LambdaQueryChainWrapper<>(this.userMapper)
                .and(wrapper -> {
                    Iterator<String> it = tagCodes.iterator();
                    while (it.hasNext()) {
                        wrapper.apply("JSON_CONTAINS(tag, JSON_OBJECT('tag_code',{0}))", it.next());
                        wrapper.or();
                    }
                })
                .orderByAsc(UserEntity::getId)
                .list();
更多使用语法参考:MySQL-JSON函数手册