• [Mybatis-Plus笔记] MybatisPlus-03-QueryWrapper条件构造器


    一、准备工作

    为了更好的理解条件构造器,建议配置 Mybatis-Plus 的日志输出到控制台

    在 yaml 配置文件中加入下面内容:

    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
    • 1
    • 2
    • 3

    如此配置后,我们可以在控制台看到 Mybatis-Plus 生成的 SQL 语句

    二、条件构造器入门

    1. 使用方式

    (1)普通 QueryWrapper

    下面的测试类中,实现了从表中查询 age 字段小于 20 的用户

    然后利用 selectList 方法,将条件构造器作为参数传入,即可得到符合条件的数据

    @SpringBootTest
    public class MybatisPlusTest {
        @Autowired
        UserMapper userMapper;
        @Test
        void testQueryWrapper() {
            QueryWrapper condition = new QueryWrapper();
            // 方法名 lt 表示小于,参数是字段名与值
            condition.lt("age", 20);
            List<User> users = userMapper.selectList(condition);
            System.out.println(users);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    [注意]

    • 不指定 QueryWrapper 的泛型无法进行链式编程

    SQL 语句为:

    SELECT id,name,age,email FROM user WHERE (age < ?)
    
    • 1

    (2)lambda 方式 QueryWrapper

    通过指定实体类的 get 方法来确定列,避免了写错类名带来的麻烦

    需要指定泛型为实体类,并以 lambda() 方法开头

    可以链式编程

    @SpringBootTest
    public class MybatisPlusTest {
        @Autowired
        UserMapper userMapper;
        @Test
        void testQueryWrapper() {
            QueryWrapper<User> condition = new QueryWrapper<User>();
    //        condition.lt("age", 20);
            condition.lambda().lt(User::getAge, 20);
            List<User> users = userMapper.selectList(condition);
            System.out.println(users);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    SQL 语句也是:

    SELECT id,name,age,email FROM user WHERE (age < ?)
    
    • 1

    (3)LambdaQueryWrapper

    使用 LambdaQueryWrapper 就不用指定再写 lambda() 方法开头了

    但不可再通过列名来指定字段

    @SpringBootTest
    public class MybatisPlusTest {
        @Autowired
        UserMapper userMapper;
        @Test
        void testQueryWrapper() {
            LambdaQueryWrapper<User> condition = new LambdaQueryWrapper<User>();
    //        condition.lt("age", 20);  // 不可用
            condition.lt(User::getAge, 20);
            List<User> users = userMapper.selectList(condition);
            System.out.println(users);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    SQL 语句依然是:

    SELECT id,name,age,email FROM user WHERE (age < ?)
    
    • 1

    2. 条件的逻辑连接

    (1)与运算

    对同一个条件构造器添加多个条件,默认用与运算(或者说且运算)连接

    如下例完成 20 <= age <= 30 的条件构造(ge 和 le 分别表示 >= 和 <=)

    @SpringBootTest
    public class MybatisPlusTest {
        @Autowired
        UserMapper userMapper;
        @Test
        void testQueryWrapper() {
            QueryWrapper<User> condition = new QueryWrapper<User>();
            condition.lambda()
                    .ge(User::getAge, 20).le(User::getAge, 30);
            List<User> users = userMapper.selectList(condition);
            System.out.println(users);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    SQL 语句为:

    SELECT id,name,age,email FROM user WHERE (age >= ? AND age <= ?)
    
    • 1

    (2)或运算

    多个条件间用 or() 方法分隔,条件就会用或运算连接

    如下例完成 age < 20 || age > 30 的条件构造(lt 和 gt 分别表示 < 和 >)

    @SpringBootTest
    public class MybatisPlusTest {
        @Autowired
        UserMapper userMapper;
        @Test
        void testQueryWrapper() {
            QueryWrapper<User> condition = new QueryWrapper<User>();
            condition.lambda().
                    lt(User::getAge, 20).or().gt(User::getAge, 30);
            List<User> users = userMapper.selectList(condition);
            System.out.println(users);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    SQL 语句为:

    SELECT id,name,age,email FROM user WHERE (age < ? OR age > ?)
    
    • 1

    (3)括号

    条件构造器中,and() 方法表示括号(或者说嵌套),而不是且运算

    我们需要将括号中的内容作为参数传入 and() 方法

    例如,我们需要在年龄低于 20 或者高于 35 的用户中,找出使用 @gmail 邮箱的用户

    可以像下面这样:

    @SpringBootTest
    public class MybatisPlusTest {
        @Autowired
        UserMapper userMapper;
        @Test
        void testQueryWrapper() {
            QueryWrapper<User> condition = new QueryWrapper<User>();
            condition.lambda()
                    .and(
                            i -> i.lt(User::getAge, 20).or().gt(User::getAge, 35)
                    ).likeLeft(User::getEmail, "@gmail.com");
            List<User> users = userMapper.selectList(condition);
            System.out.println(users);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    关于 and() 方法中的 lambda 表达式,在 idea 中 按住 ctrl 将鼠标放在 i 上,可以看到,i 指代的是一个 LambdaQueryWrapper

    在这里插入图片描述

    SQL 语句为:

    SELECT id,name,age,email FROM user WHERE ((age < ? OR age > ?) AND email LIKE ?)
    
    • 1

    参数为 :

    Parameters: 20(Integer), 35(Integer), %@gmail.com(String)
    
    • 1

    可见 likeLeft() 方法自动给参数左侧加上了 % 通配符
    类似的还有 likeRight() 在右侧加 %
    like() 在左右侧都加 %

    3. 更多条件判断方法

    lt, le, gt, ge 这些代表条件判断的代码,最早还是在 Shell 脚本中见到的

    想要了解更多的话推荐这一篇文章:Mybatis Plus详解(三)——条件构造器详解

    三、补充

    1. 增加布尔值参数

    在条件构造器添加条件是,可以再加入一个 boolean 值表示是否要将此条件加入。

    看下例中,服务层实现了根据年龄区间查询用户的功能:

    @Service
    public class UserServiceImpl implements UserService {
        @Autowired
        UserMapper userMapper;
    
        @Override
        public List<User> selectByAgeRange(Integer low, Integer high) {
            QueryWrapper<User> condition = new QueryWrapper<>();
            condition.lambda()
                    .ge(User::getAge, low)
                    .lt(User::getAge, high);
            return userMapper.selectList(condition);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    但是参数为 null 时会怎样呢?测试一下看看:

    @SpringBootTest
    public class UserServiceTest {
        @Autowired
        UserService userService;
        @Test
        void testSelectByAgeRange() {
            List<User> users = userService.selectByAgeRange(null, 20);
            System.out.println(users);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    用 null 和 20 做参数,一般希望能忽略下限,查询小于 20 岁的用户,但实际上没有查到任何结果

    Mybatis-Plus 日志如下:

    ==>  Preparing: SELECT id,name,age,email FROM user WHERE (age >= ? AND age < ?)
    ==> Parameters: null, 20(Integer)
    <==      Total: 0
    
    • 1
    • 2
    • 3

    如果某个参数为空,则不将此条件加入构造,可以这样写:

    @Service
    public class UserServiceImpl implements UserService {
        @Autowired
        UserMapper userMapper;
    
        @Override
        public List<User> selectByAgeRange(Integer low, Integer high) {
            QueryWrapper<User> condition = new QueryWrapper<>();
            condition.lambda()
                    .ge(low != null, User::getAge, low)
                    .lt(high != null, User::getAge, high);
            return userMapper.selectList(condition);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    ge 和 lt 方法中多了一个布尔值参数,当这个参数为真时才会加入此条件

    再次执行测试,日志如下:

    ==>  Preparing: SELECT id,name,age,email FROM user WHERE (age < ?)
    ==> Parameters: 20(Integer)
    <==    Columns: id, name, age, email
    <==        Row: 2, Tao Chi Yuen, 17, chiyuentao@icloud.com
    <==        Row: 4, Ueno Hikari, 18, hikari9@hotmail.com
    <==        Row: 12, Mildred Ramirez, 19, ramirez2@icloud.com
    <==      Total: 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2. 查询映射

    select() 方法可以指定查询的内容,参数为字符串可变参数,将表的字段名做为参数传入

    默认查询所有字段,如果没有参数传入则无效

    Mybatis-Plus 会在多个参数间添加逗号,然后放在 SQL 语句的 SELECT 之后

    我们直接用 SQL 语句作为参数传入也可以

    select() 方法的效果不会叠加,多次调用 select() 方法时以最后一次为准,最后一次无参数不会覆盖之前的

    示例:

    @SpringBootTest
    public class MybatisPlusTest {
        @Autowired
        UserMapper userMapper;
        @Test
        void testSelect() {
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.select("age");
            wrapper.select("name, email");
            wrapper.select("name AS userName, email AS userEmail");
            wrapper.select();
            userMapper.selectList(wrapper);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Mybatis-Plus 日志如下:

    ==>  Preparing: SELECT name AS userName, email AS userEmail FROM user
    ==> Parameters: 
    <==    Columns: userName, userEmail
    <==        Row: Pauline Cole, paulic59@icloud.com
    <==        Row: Tao Chi Yuen, chiyuentao@icloud.com
    <==      Total: 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3. selectMaps() 方法

    如果查询到的数据是不能装进实体类中的,就要调用 selectMaps() 方法了,用 List> 接收结果

    比如聚合函数查询平均年龄,如下:

    @SpringBootTest
    public class MybatisPlusTest {
        @Autowired
        UserMapper userMapper;
        @Test
        void testSelectMaps() {
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.select("AVG(age) AS averageAge");
            List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
            
            System.out.println(maps);
            BigDecimal averageAge = (BigDecimal) maps.get(0).get("averageAge");
            System.out.println("averageAge = " + averageAge);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    另外,AVG() 聚合函数得到的结果是 BigDecimal 类型,而不是 double

    Mybatis-Plus 日志如下:

    ==>  Preparing: SELECT AVG(age) AS averageAge FROM user
    ==> Parameters: 
    <==    Columns: averageAge
    <==        Row: 21.8438
    <==      Total: 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    【5G MAC】RA-RNTI的计算过程
    查询PCIE设备的VID,DID,SVID,SDID
    【设计模式】【创建型5-2】【工厂方法模式】
    纯js实现录屏并保存视频到本地的尝试
    私藏!资深数据专家SQL效率优化技巧
    Python开发者必读:Pip使用全攻略与最佳实践
    关于旅游景点主题的HTML网页设计——青岛民俗 7页 带登录注册
    微服务网关Gateway实践总结
    【深入理解TcaplusDB技术】一键安装Tmonitor后台
    做外贸真诚是最好的套路
  • 原文地址:https://blog.csdn.net/Cey_Tao/article/details/126797095