MySQL 中查询 VARCHAR 类型 JSON 数据的

在数据库设计中,有时我们会将 JSON 数据存储在 VARCHAR 或 TEXT 类型字段中。这种方式虽然灵活,但在查询时需要特别注意。本文将详细介绍如何在 MySQL 中有效查询存储为 VARCHAR 类型的 JSON 数据。

一、问题背景

当 JSON 数据存储在 VARCHAR 列中时,常见的数据格式如下:

复制代码
[
  {"id":"1905555466980773889","hasPermission":true},
  {"id":"1905547884060835841","hasPermission":false}
]

我们需要查询这个 JSON 数组中是否包含特定 ID 的对象。

二、MySQL JSON 函数

MySQL 5.7+ 版本提供了丰富的 JSON 处理函数,即使数据类型是 VARCHAR,只要内容是有效的 JSON,我们仍然可以使用这些函数:

2.1 常用 JSON 函数

  • JSON_CONTAINS(target, candidate[, path]): 检查 JSON 文档是否包含特定值
  • JSON_EXTRACT(json_doc, path): 从 JSON 文档中提取值
  • JSON_OBJECT(key, val[, key, val]...): 创建 JSON 对象
  • JSON_ARRAY(val[, val]...): 创建 JSON 数组
  • JSON_VALID(json_doc): 验证字符串是否为有效的 JSON

三、查询示例

3.1 基本查询

查询 JSON 数组中包含特定 ID 的记录:

复制代码
SELECT * FROM sys_user
WHERE 
  app_ids IS NOT NULL
  AND app_ids != ''
  AND JSON_CONTAINS(app_ids, JSON_OBJECT('id', '1905555466980773889'));

3.2 查询多个 ID

复制代码
SELECT * FROM sys_user
WHERE 
  app_ids IS NOT NULL
  AND app_ids != ''
  AND (
    JSON_CONTAINS(app_ids, JSON_OBJECT('id', '1905555466980773889'))
    OR JSON_CONTAINS(app_ids, JSON_OBJECT('id', '1905547884060835841'))
  );

3.3 使用 JSON_OVERLAPS (MySQL 8.0+)

复制代码
SELECT * FROM sys_user
WHERE 
  app_ids IS NOT NULL
  AND app_ids != ''
  AND JSON_OVERLAPS(
    app_ids, 
    JSON_ARRAY(
      JSON_OBJECT('id', '1905555466980773889'),
      JSON_OBJECT('id', '1905547884060835841')
    )
  );

3.4 查询特定权限的记录

复制代码
SELECT * FROM sys_user
WHERE 
  app_ids IS NOT NULL
  AND app_ids != ''
  AND JSON_CONTAINS(
    app_ids, 
    JSON_OBJECT('id', '1905555466980773889', 'hasPermission', true)
  );

四、避免常见错误

4.1 空值处理

JSON_CONTAINS 函数在处理 NULL 或空字符串时会报错,所以需要先排除这些情况:

复制代码
-- 错误做法
SELECT * FROM sys_user WHERE JSON_CONTAINS(app_ids, JSON_OBJECT('id', '123'));

-- 正确做法
SELECT * FROM sys_user 
WHERE 
  app_ids IS NOT NULL 
  AND app_ids != '' 
  AND JSON_CONTAINS(app_ids, JSON_OBJECT('id', '123'));

4.2 JSON 格式匹配

确保 JSON_CONTAINS 的第二个参数结构与目标 JSON 中的结构匹配:

复制代码
-- 错误做法 (直接传入 ID 字符串)
SELECT * FROM sys_user WHERE JSON_CONTAINS(app_ids, '"1905555466980773889"');

-- 正确做法 (创建与数组元素匹配的对象)
SELECT * FROM sys_user WHERE JSON_CONTAINS(app_ids, JSON_OBJECT('id', '1905555466980773889'));

4.3 确保 JSON 有效性

添加 JSON_VALID 检查确保字段内容是有效的 JSON:

复制代码
SELECT * FROM sys_user
WHERE 
  app_ids IS NOT NULL
  AND app_ids != ''
  AND JSON_VALID(app_ids) = 1
  AND JSON_CONTAINS(app_ids, JSON_OBJECT('id', '1905555466980773889'));

五、在 MyBatis Plus 中的应用

5.1 基本查询

复制代码
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.isNotNull(SysUser::getAppIds)
            .ne(SysUser::getAppIds, "")
            .apply("JSON_CONTAINS(app_ids, JSON_OBJECT('id', {0}))", "1905555466980773889");

List<SysUser> userList = sysUserMapper.selectList(queryWrapper);

5.2 多条件查询

复制代码
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
queryWrapper.isNotNull("app_ids")
            .ne("app_ids", "")
            .apply("JSON_VALID(app_ids) = 1")
            .apply("JSON_CONTAINS(app_ids, JSON_OBJECT('id', {0}))", "1905555466980773889");

// 如果还要根据权限过滤
queryWrapper.apply("JSON_CONTAINS(app_ids, JSON_OBJECT('id', {0}, 'hasPermission', {1}))", 
                   "1905555466980773889", true);

5.3 查询多个 ID

复制代码
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.isNotNull(SysUser::getAppIds)
            .ne(SysUser::getAppIds, "")
            .and(w -> w.apply("JSON_CONTAINS(app_ids, JSON_OBJECT('id', {0}))", "1905555466980773889")
                      .or()
                      .apply("JSON_CONTAINS(app_ids, JSON_OBJECT('id', {0}))", "1905547884060835841"));

List<SysUser> userList = sysUserMapper.selectList(queryWrapper);

六、性能优化建议

  1. 考虑使用 JSON 类型:如果您的 MySQL 版本是 5.7+,考虑使用原生 JSON 类型代替 VARCHAR,这样可以获得更好的性能和功能支持。

  2. 添加索引:虽然无法直接为 JSON 内容创建索引,但可以使用生成的列和函数索引:

    复制代码
    ALTER TABLE sys_user ADD COLUMN app_id_extracted JSON 
      GENERATED ALWAYS AS (JSON_EXTRACT(app_ids, '$[*].id')) VIRTUAL;
    
    ALTER TABLE sys_user ADD INDEX idx_app_id_extracted (app_id_extracted);
  3. 定期维护:对于大表,定期 OPTIMIZE TABLE 有助于维护性能。

七、总结

在 MySQL 中查询 VARCHAR 类型的 JSON 数据时,关键是:

  1. 使用 JSON_CONTAINS 函数并构造正确的 JSON 结构进行匹配
  2. 处理好 NULL 和空字符串
  3. 验证 JSON 有效性
  4. 在 MyBatis Plus 中使用 apply 方法添加原生 SQL 条件

正确使用这些技术可以有效地查询和处理 VARCHAR 中存储的 JSON 数据。

相关推荐
moxiaoran575320 分钟前
mysql自动赋值
数据库·mysql
结衣结衣.24 分钟前
【MySQL】数据库基础
数据库·mysql
看海的四叔1 小时前
【SQL】MySql常见的性能优化方式
hive·sql·mysql·性能优化·数据分析·索引优化·sql语法
路在脚下@1 小时前
Spring Boot项目中结合MyBatis实现MySQL的自动主从切换
spring boot·mysql·mybatis
x-cmd1 小时前
x-cmd install | jellex - 用 Python 语法在终端里玩转 JSON 数据!
开发语言·python·json·命令行终端
Bartender_Jill2 小时前
【Claude AI大语言模型连接Blender生成资产】Windows安装Blender MCP教程
人工智能·语言模型·json·游戏引擎·blender
kylinxjd2 小时前
Windows单机模拟MySQL主从复制
windows·mysql·主从复制
暗恋 懒羊羊3 小时前
【MySQL】表的增删改查
数据库·mysql
怒放的生命.6 小时前
《MySQL从入门到精通》
android·数据库·mysql
略知java的景初8 小时前
MYSQL MVCC详解
mysql