目录

MyBatis-Plus 查询构建实战:eq/between/in/or/like likeLeft likeRight/gte和lte/动态条件


MyBatis-Plus 查询构建实战:从零到精通条件构造器

MyBatis-Plus(简称 MP)的查询构建功能是个大杀器,尤其是它的 QueryWrapper,能让你像搭积木一样拼出各种查询条件。这篇博客不整虚的,直接上大量实例,带你把这块玩熟。咱们会从 Mapper 和 Service 层代码开始,一步步搞定常见的查询场景。

1. 先搭个基础环境

假设我们用 Spring Boot + MySQL,项目里得加依赖:

xml 复制代码
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.33</version>
</dependency>

配置文件(application.yml):

yaml 复制代码
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test_db?useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

表结构用两个:user(用户表)和 order(订单表),方便后面多表联查:

  • userid (bigint)、username (varchar)、age (int)、status (int, 0=禁用, 1=启用)
  • orderid (bigint)、user_id (bigint)、order_name (varchar)、amount (decimal)

2. 实体类、Mapper 和 Service 代码

2.1 实体类

先把实体类写好:

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

@Data
@TableName("user")
public class User {
    private Long id;
    private String username;
    private Integer age;
    private Integer status;
}

@Data
@TableName("order")
public class Order {
    private Long id;
    private Long userId;
    private String orderName;
    private BigDecimal amount;
}
2.2 Mapper 层

Mapper 继承 BaseMapper,基础 CRUD 都不用写,后面加点自定义查询:

java 复制代码
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;
import java.util.Map;

public interface UserMapper extends BaseMapper<User> {
    // 自定义多表联查
    @Select("SELECT u.*, o.order_name, o.amount FROM user u LEFT JOIN `order` o ON u.id = o.user_id WHERE u.status = 1")
    List<Map<String, Object>> selectActiveUsersWithOrders();
}

public interface OrderMapper extends BaseMapper<Order> {
}
2.3 Service 层

Service 层继承 IService,再写个实现类封装查询逻辑:

java 复制代码
import com.baomidou.mybatisplus.extension.service.IService;

public interface UserService extends IService<User> {
    List<User> findByAgeRange(Integer minAge, Integer maxAge);
    List<User> findByNameLike(String keyword);
    List<Map<String, Object>> findActiveUsersWithOrders();
}

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Override
    public List<User> findByAgeRange(Integer minAge, Integer maxAge) {
        return baseMapper.selectList(new QueryWrapper<User>()
            .between("age", minAge, maxAge));
    }

    @Override
    public List<User> findByNameLike(String keyword) {
        return baseMapper.selectList(new QueryWrapper<User>()
            .like("username", keyword));
    }

    @Override
    public List<Map<String, Object>> findActiveUsersWithOrders() {
        return baseMapper.selectActiveUsersWithOrders();
    }
}

public interface OrderService extends IService<Order> {
}

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
}

分页得加个配置:

java 复制代码
@Configuration
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

3. QueryWrapper 实战:各种查询场景

好了,基础搭好了,咱们直接上实例,玩转 QueryWrapper

3.1 简单等值查询

username = "张三" 的用户:

java 复制代码
@SpringBootTest
class QueryWrapperTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    void testEqual() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", "张三");
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
}

eq 是等于,简单直接。

3.2 范围查询

查年龄在 20-30 之间的用户:

java 复制代码
@Test
void testBetween() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.between("age", 20, 30);
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

between 包含边界值,查个范围特别方便。

3.3 模糊查询

查用户名包含"张"的:

java 复制代码
@Test
void testLike() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.like("username", "张");
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

like 是模糊匹配,左右都加 %,还有 likeLeft(左模糊)和 likeRight(右模糊)可选。

3.4 多条件组合

查年龄大于 25 且状态为启用的用户:

java 复制代码
@Test
void testMultiCondition() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.gt("age", 25)  // 大于
           .eq("status", 1); // 等于
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

gt 是大于,条件用链式调用,逻辑默认是 AND。

3.5 OR 条件

查年龄小于 20 或者状态为禁用的:

java 复制代码
@Test
void testOr() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.lt("age", 20)  // 小于
           .or()           // 或
           .eq("status", 0);
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

or() 切换成 OR 逻辑,挺灵活。

3.6 分页查询

查启用用户,按年龄倒序,第 2 页,每页 3 条:

java 复制代码
@Test
void testPage() {
    Page<User> page = new Page<>(2, 3); // 第2页,每页3条
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("status", 1)
           .orderByDesc("age");
    Page<User> result = userMapper.selectPage(page, wrapper);
    System.out.println("总条数: " + result.getTotal());
    result.getRecords().forEach(System.out::println);
}

orderByDesc 是倒序,orderByAsc 是正序。

3.7 动态条件

根据输入动态拼条件,比如年龄范围可选:

java 复制代码
@Test
void testDynamic() {
    Integer minAge = 20; // 可为空
    Integer maxAge = null;
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.ge(minAge != null, "age", minAge) // 大于等于,可动态加
           .le(maxAge != null, "age", maxAge); // 小于等于,可动态加
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

gele 第一个参数是布尔值,条件成立才加进去,动态查询很实用。

3.8 IN 查询

查 ID 在某个列表里的用户:

java 复制代码
@Test
void testIn() {
    List<Long> ids = Arrays.asList(1L, 2L, 3L);
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.in("id", ids);
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

in 支持集合,查多值很方便。

4. 多表联查场景

单表玩腻了,咱们试试多表。需求:查启用用户和他们的订单。

4.1 用 Service 两次查询

先查用户,再查订单:

java 复制代码
@Autowired
private UserService userService;
@Autowired
private OrderService orderService;

@Test
void testMultiTable() {
    List<User> users = userService.list(new QueryWrapper<User>().eq("status", 1));
    for (User user : users) {
        List<Order> orders = orderService.list(new QueryWrapper<Order>().eq("user_id", user.getId()));
        System.out.println(user.getUsername() + " 的订单:");
        orders.forEach(order -> System.out.println(order.getOrderName() + " - " + order.getAmount()));
    }
}

简单,但查两次,数据量大时有点慢。

4.2 自定义 SQL 联查

直接用 Mapper 里的自定义方法:

java 复制代码
@Test
void testCustomJoin() {
    List<Map<String, Object>> result = userService.findActiveUsersWithOrders();
    result.forEach(System.out::println);
}

输出可能是:

ini 复制代码
{id=1, username=张三, age=25, status=1, order_name=手机, amount=1999.00}
{id=2, username=李四, age=30, status=1, order_name=电脑, amount=5999.00}

一次查完,效率高。

5. 小结

MyBatis-Plus 的 QueryWrapper 真是个好帮手,等值、范围、模糊、多条件、分页、动态查询啥都能搞定。单表用 BaseMapperIService 就很舒服,多表联查稍微麻烦点,可以两次查询凑合,或者写自定义 SQL 一步到位。

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
盖世英雄酱581362 小时前
JDK24 它来了,抗量子加密
java·后端
Asthenia04123 小时前
无感刷新的秘密:Access Token 和 Refresh Token 的那些事儿
前端·后端
Asthenia04123 小时前
面试复盘:聊聊epoll的原理、以及其相较select和poll的优势
后端
luckyext3 小时前
SQLServer列转行操作及union all用法
运维·数据库·后端·sql·sqlserver·运维开发·mssql
Asthenia04124 小时前
ES:倒排索引的原理与写入分析
后端
圈圈编码4 小时前
Spring常用注解汇总
java·后端·spring
stark张宇5 小时前
PHP多版本共存终极填坑指南:一台服务器部署多实例的最佳实践
后端·php
Lian_Aseubel5 小时前
Springboot整合Netty简单实现1对1聊天(vx小程序服务端)
java·spring boot·后端
m0_748254886 小时前
SpringBoot整合MQTT最详细版(亲测有效)
java·spring boot·后端
uhakadotcom6 小时前
Kubernetes入门指南:从基础到实践
后端·面试·github