MyBatis-Plus LambdaQuery 高级用法:JSON 路径查询与条件拼接的全场景解析

目录

[1. 查询 JSON 字段中的特定值](#1. 查询 JSON 字段中的特定值)

[2. 动态查询 JSON 字段中的值](#2. 动态查询 JSON 字段中的值)

[3. 查询 JSON 数组中的值](#3. 查询 JSON 数组中的值)

[4. 查询 JSON 字段中的嵌套对象](#4. 查询 JSON 字段中的嵌套对象)

[5. 结合其他条件查询 JSON 字段](#5. 结合其他条件查询 JSON 字段)

[6. 使用类型处理器简化 JSON 查询](#6. 使用类型处理器简化 JSON 查询)

[6.1 创建自定义 JSON 类型处理器](#6.1 创建自定义 JSON 类型处理器)

[6.2 在实体类中指定自定义类型处理器](#6.2 在实体类中指定自定义类型处理器)

示例代码

[6.3 配置类型处理器包(可选)](#6.3 配置类型处理器包(可选))

[6.4 使用自定义类型处理器](#6.4 使用自定义类型处理器)

[7. 使用内置的 JacksonTypeHandler 或 FastjsonTypeHandler](#7. 使用内置的 JacksonTypeHandler 或 FastjsonTypeHandler)

1. 查询 JSON 字段中的特定值

假设有一个表 user,其中包含一个 JSON 字段 info,存储了用户的一些额外信息。如果要查询 info 字段中 age 大于 20 的用户,可以使用以下代码:

java 复制代码
LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
queryWrapper.apply("JSON_EXTRACT(info, '$.age') > {0}", 20);
List<User> users = userMapper.selectList(queryWrapper);

这里通过 apply 方法嵌入了 MySQL 的 JSON_EXTRACT 函数。

2. 动态查询 JSON 字段中的值

如果需要根据动态条件查询 JSON 字段中的值,例如根据用户输入的条件查询 info 字段中 gender"male" 的用户,可以这样实现:

java 复制代码
LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
if ("male".equals(gender)) {
    queryWrapper.apply("JSON_EXTRACT(info, '$.gender') = {0}", "\"male\"");
}
List<User> users = userMapper.selectList(queryWrapper);

这种方式可以根据条件动态添加查询语句。

3. 查询 JSON 数组中的值

假设 info 字段是一个 JSON 数组,存储了用户的多个兴趣爱好,要查询兴趣爱好中包含 "reading" 的用户:

java 复制代码
LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
queryWrapper.apply("JSON_CONTAINS(info, {0})", "\"reading\"");
List<User> users = userMapper.selectList(queryWrapper);

这里使用了 MySQL 的 JSON_CONTAINS 函数。

4. 查询 JSON 字段中的嵌套对象

如果 JSON 字段中包含嵌套对象,例如 info 字段中有一个 address 对象,要查询 address 中的 city"Beijing" 的用户:

java 复制代码
LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
queryWrapper.apply("JSON_EXTRACT(info, '$.address.city') = {0}", "\"Beijing\"");
List<User> users = userMapper.selectList(queryWrapper);

通过指定 JSON 路径,可以查询嵌套对象中的值。

5. 结合其他条件查询 JSON 字段

可以将 JSON 字段的查询与其他普通字段的查询条件结合使用。例如,查询状态为 "active"info 字段中 age 大于 20 的用户:

java 复制代码
LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
queryWrapper.eq(User::getStatus, "active")
             .apply("JSON_EXTRACT(info, '$.age') > {0}", 20);
List<User> users = userMapper.selectList(queryWrapper);

这种方式可以灵活地组合多种查询条件。

6. 使用类型处理器简化 JSON 查询

从 MyBatis-Plus 3.5.3.2 版本开始,可以在 Wrapper 查询中直接使用类型处理器。例如,假设有一个自定义的 JSON 类型处理器 UserInfoTypeHandler,可以这样使用:

java 复制代码
LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
queryWrapper.apply("info = {0, typeHandler=" + UserInfoTypeHandler.class.getCanonicalName() + "}", "{\"age\":20,\"gender\":\"male\"}");
List<User> users = userMapper.selectList(queryWrapper);

通过类型处理器,可以更方便地处理 JSON 数据

6.1 创建自定义 JSON 类型处理器

自定义的 JSON 类型处理器需要继承 BaseTypeHandlerAbstractJsonTypeHandler 等内置类型处理器,并实现相关方法。

示例代码

以下是一个基于 Jackson 的自定义 JSON 类型处理器示例:

java 复制代码
import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@MappedTypes({Object.class}) // 指定支持的 Java 类型
@MappedJdbcTypes(JdbcType.VARCHAR) // 指定对应的 JDBC 类型
public class CustomJsonTypeHandler<T> extends AbstractJsonTypeHandler<T> {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    public CustomJsonTypeHandler(Class<T> type) {
        super(type);
    }

    @Override
    protected T parse(String json) {
        try {
            return objectMapper.readValue(json, getType());
        } catch (Exception e) {
            throw new RuntimeException("Failed to parse JSON", e);
        }
    }

    @Override
    protected String toJson(T obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            throw new RuntimeException("Failed to serialize object to JSON", e);
        }
    }
}
6.2 在实体类中指定自定义类型处理器

在实体类中,通过 @TableField 注解指定自定义的类型处理器。

示例代码

假设有一个 User 实体类,其中 info 字段是一个 JSON 字段,存储用户的一些额外信息:

java 复制代码
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;

@Data
@TableName(value = "user", autoResultMap = true)
public class User {
    private Long id;
    private String name;

    @TableField(typeHandler = CustomJsonTypeHandler.class)
    private UserInfo info; // UserInfo 是一个自定义的 Java 类
}
6.3 配置类型处理器包(可选)

如果自定义的类型处理器不在默认扫描路径下,可以在 application.yml 中指定类型处理器的包路径:

XML 复制代码
mybatis-plus:
  type-handlers-package: com.yourpackage.handler
6.4 使用自定义类型处理器

在 MyBatis-Plus 的增删改查操作中,自定义的类型处理器会自动生效。例如:

java 复制代码
User user = new User();
user.setName("Alice");
user.setInfo(new UserInfo("Beijing", 25)); // 设置 JSON 字段
userMapper.insert(user);

// 查询时,info 字段会自动解析为 UserInfo 对象
User queriedUser = userMapper.selectById(user.getId());
System.out.println(queriedUser.getInfo().getCity()); // 输出 Beijing

通过以上步骤,你可以在 MyBatis-Plus 中使用自定义的 JSON 类型处理器来处理数据库中的 JSON 字段

7. 使用内置的 JacksonTypeHandlerFastjsonTypeHandler

MyBatis-Plus 提供了内置的 JSON 类型处理器,如 JacksonTypeHandlerFastjsonTypeHandler,可以直接将 JSON 字段映射为 JSONObject 或其他 JSON 类型。

示例代码

假设有一个表 user,其中 info 是一个 JSON 字段,存储用户的一些额外信息。在实体类中,可以这样配置:

java 复制代码
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;

@Data
@TableName("user")
public class User {
    private Long id;
    private String name;

    @TableField(typeHandler = JacksonTypeHandler.class)
    private JSONObject info; // 使用 JSONObject
}

在 MyBatis-Plus 的增删改查操作中,info 字段会自动被解析为 JSONObject

相关推荐
葬歌倾城1 小时前
JSON的缩进格式方式和紧凑格式方式
c#·json
梦在深巷、1 小时前
MySQL/MariaDB数据库主从复制之基于二进制日志的方式
linux·数据库·mysql·mariadb
Johny_Zhao2 小时前
Ubuntu系统安装部署Pandawiki智能知识库
linux·mysql·网络安全·信息安全·云计算·shell·yum源·系统运维·itsm·pandawiki
耀耀_很无聊2 小时前
07_通过 Mybatis 自动填充记录的创建时间和更新时间
mybatis
祁思妙想2 小时前
八股学习(三)---MySQL
数据库·学习·mysql
惊骇世俗王某人3 小时前
1.MySQL之如何定位慢查询
数据库·mysql
程序员张33 小时前
SQL分析与打印-p6spy组件
spring boot·sql·mybatis·mybatisplus·p6spy
叁沐3 小时前
MySQL 04 深入浅出索引(上)
mysql
q9085447034 小时前
MySQL 二进制日志binlog解析
mysql·binlog·binlog2sql·my2sql
码不停蹄的玄黓5 小时前
MySQL分布式ID冲突详解:场景、原因与解决方案
数据库·分布式·mysql·id冲突