在 MyBatis-Plus 中对 TEXT 存储的 JSON 字符串实现多标签(tags)模糊查询
🌟 场景描述
在许多项目中,为了简化表结构,我们会将一对多的标签数据序列化为 JSON 字符串,存入数据库的 TEXT 字段。例如:
-- 表结构示例
CREATE TABLE question (
id BIGINT PRIMARY KEY,
title VARCHAR(255),
tags TEXT -- 存储如:["Java", "Spring", "MyBatis"]
);前端通过接口传入一个标签列表:
{
"tags": ["Java", "Redis"]
}需求:查询所有同时包含 “Java” 和 “Redis” 标签的问题(即交集查询)。
💡 注意:虽然字段是
TEXT,但内容是合法的 JSON 数组格式,因此仍可借助数据库的 JSON 函数进行解析。
⚠️ 为什么不推荐 LIKE 模糊匹配?
一般我们会这样写:
wrapper.like("tags", "%Java%").like("tags", "%Redis%");但这种方式存在严重缺陷:
❌ 误匹配:"
JavaScript" 会被 "Java" 错误命中;❌ 边界问题:无法区分 "
Go" 和 "Golang";❌ 语义错误:破坏了 JSON 数据的结构化含义。
✅ 正确方案:使用 JSON_CONTAINS 解析 TEXT 中的 JSON
即使 tags 是 TEXT 类型,只要其内容是合法的 JSON 字符串,MySQL 5.7+ 依然能通过 JSON_CONTAINS 函数正确解析并匹配。
🔧 实现代码(MyBatis-Plus)
import cn.hutool.core.collection.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
public LambdaQueryWrapper<Question> buildQueryWrapper(List<String> tags) {
LambdaQueryWrapper<Question> queryWrapper = Wrappers.lambdaQuery();
if (!CollectionUtils.isEmpty(tags)) {
for (String tag : tags) {
// 将 tag 转为 JSON 字符串字面量:"tag"
String jsonTag = "\"" + tag + "\"";
queryWrapper.apply("JSON_CONTAINS(tags, ?)", jsonTag);
}
}
return queryWrapper;
}💡 关键说明
🧪 生成的 SQL 示例
当前端传入 ["Java", "Redis"] 时,实际执行的 SQL 为:
SELECT * FROM question
WHERE JSON_CONTAINS(tags, 'Java')
AND JSON_CONTAINS(tags, 'Redis');✅ 精确匹配:["JavaScript", "Redis"] 不会被查出
✅ 结构感知:正确识别 JSON 数组中的独立元素
JSON_CONTAINS在TEXT字段上无法使用普通索引
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 疯狂彩虹屁
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果