MybatisPlus中and和or的使用&MybatisPlus遇到的and和or优先级的问题处理

曾经终败给现在 2023-09-30 23:53 89阅读 0赞

MybatisPlus中and和or的使用

需求

最近自己玩发现MyBatisPlus还是挺好用的,但是忽然发现对于一个持久层框架来说支持拼接复杂的SQL也是一个优势,对一个持久层框架拼接SQL来说,or比and更难拼,所以此处用案例来实现MybatisPlus中or和and的简单使用。

MybatisPlus中and和or的使用\_spring boot

and和or的使用

案例1:AandB
  1. @GetMapping("/AandB")
  2. public Object AandB(){
  3. //SELECT id,name,age,sex FROM student WHERE (name = ? AND age = ?)
  4. List<Student> list = studentService.lambdaQuery().eq(Student::getName, "1").eq(Student::getAge, 1).list();
  5. return list;
  6. }
案例2:AorB
  1. @GetMapping("/AorB")
  2. public Object AorB(){
  3. //SELECT id,name,age,sex FROM student WHERE (name = ? OR age = ?)
  4. List<Student> list = studentService.lambdaQuery().eq(Student::getName, "1").or().eq(Student::getAge, 12).list();
  5. return list;
  6. }
案例3:A or(C and D)
  1. @GetMapping("/A_or_CandD")
  2. public Object A_or_CandD() {
  3. //SELECT id,name,age,sex FROM student WHERE (name = ? OR (name = ? AND age = ?))
  4. List<Student> list =
  5. studentService
  6. .lambdaQuery()
  7. .eq(Student::getName, "1")
  8. .or(wp -> wp.eq(Student::getName, "1").eq(Student::getAge, 12))
  9. .list();
  10. return list;
案例4:(AandB)or(CandD)
  1. @GetMapping("/AandB_or_CandD")
  2. public Object AandB_or_CandD() {
  3. // SELECT id,name,age,sex FROM student WHERE ((name = ? AND age = ?) OR (name = ? AND age = ?))
  4. List<Student> list =
  5. studentService
  6. .lambdaQuery()
  7. .and(wp -> wp.eq(Student::getName, "1").eq(Student::getAge, 12))
  8. .or(wp -> wp.eq(Student::getName, "1").eq(Student::getAge, 12))
  9. .list();
  10. return list;
  11. }
案例5:A or (B and ( C or D))
  1. @GetMapping("/complex")
  2. public Object complex() {
  3. // SELECT * FROM student WHERE ((name <> 1) OR (name = 1 AND (age IS NULL OR age >= 11)))
  4. List<Student> list =
  5. studentService
  6. .lambdaQuery()
  7. .and(wp -> wp.ne(Student::getName, "1"))
  8. .or(
  9. wp ->
  10. wp.eq(Student::getName, "1")
  11. .and(wpp -> wpp.isNull(Student::getAge).or().ge(Student::getAge, 11)))
  12. .list();
  13. return list;
  14. }

总结

1 你可以让他打印SQL语句,这样你就知道知道的SQL了

2 我遇到的情况是不报错,不打印SQL,那只能DEBUG

3 手写SQL在mapper中也行



Mybatis-Plus中的and()和or()的使用与原理介绍

一. 简单无优先级连接(即无括号的sql语句)

简单来说,两个子条件间默认and与连接,若两个之间显式写出or()则or或连接.

  1. 与连接 and()

当需要简单的将两个条件与连接,则最直接的写法为:

  1. QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().
  2. eq("attr_id",key).
  3. eq("catelog_id",catelogId);

当然也可以显式地写出and()如下,但没必要:

  1. QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().
  2. eq("attr_id",key);
  3. queryWrapper.and(qr -> qr.eq("catelog_id", catelogId));
  1. 或连接 or()

当需要简单的将两个条件或连接,则最直接的写法为:

  1. QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().
  2. eq("attr_id",key).
  3. or().
  4. eq("catelog_id",catelogId);

当然也可以如下,但不那么直观:

  1. QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().
  2. eq("attr_id",key);
  3. queryWrapper.or(qr -> qr.eq("catelog_id", catelogId));

二. 复杂有优先级的的连接

上面有2个不推荐的做法,是因为sql语句为A or B , A and B这种简单连接.当涉及到诸如 A and ( B or C) and D 这类的复杂有优先级的的连接,直接拼接会导致成为 A and B or C and D.所以这时候需要需要or(Consumer consumer),and(Consumer consumer)这两个方法.示例如下:

  1. QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().eq("attr_type", "base".equalsIgnoreCase(type) ? 1 : 0);
  2. queryWrapper.and(qr ->
  3. qr.eq("attr_id", key).
  4. or().
  5. like("attr_name", key)
  6. );
  7. queryWrapper.and(qr -> qr.eq("catelog_id", catelogId));

生成的sql语句如下:

  1. select ...
  2. WHERE (attr_type = ? AND ( (attr_id = ? OR attr_name LIKE ?) ) AND ( (catelog_id = ?) ))
  3. ...;

由此还可见or(Consumer consumer),and(Consumer consumer)这两个方法参数为Consumer时,会在连接处生成2对括号,以此提高优先级.



mybatisplus遇到的and和or优先级的问题处理

我在测试过程当中发现获取数据信息时候获取到了意想不到的数据

查看了Mybatis的查询语句:

  1. LambdaQueryWrapper<RobotAnswerLibEntity> answerWrapper = new LambdaQueryWrapper<>();
  2. answerWrapper.eq( RobotAnswerLibEntity::getProjectId, projectId );
  3. answerWrapper.eq( RobotAnswerLibEntity::getDeviceSerial, "");
  4. answerWrapper.or();
  5. answerWrapper.eq( RobotAnswerLibEntity::getDeviceSerial, dto.getDeviceSerial());

本意是想要 该projectId下,DeviceSerial为””或”输入”的所有数据。

观察它生成的sql如下:

  1. SELECT id,content,tags,device_serial,enable,display,projectid
  2. FROM tb_robot_answer_lib WHERE
  3. (projectid = 533840063904560 AND device_serial = '123abcdasd123123a' OR device_serial = '')

查询结果:
img

可以看到有很多不属于想要的数据。

问题的根本原因就是在于这个 AND 和 OR 的优先级。关系型运算符优先级高到低为:NOT > AND > OR

所以事实上执行的顺序是 先判断了
projectid = 533840063904560 AND device_serial = ‘123abcdasd123123a’
后判断了 device_serial = ‘’ ,于是就有了上面的结果。

想改也简单,需要把or左右的两个条件合并到一个()里。具体的代码修正如下:

  1. LambdaQueryWrapper<RobotAnswerLibEntity> answerWrapper = new LambdaQueryWrapper<>();
  2. answerWrapper.eq( RobotAnswerLibEntity::getProjectId, projectId );
  3. answerWrapper
  4. .and(x->x.eq( RobotAnswerLibEntity::getDeviceSerial, "" ).or().eq( RobotAnswerLibEntity::getDeviceSerial, dto.getDeviceSerial() ));

这样生成的sql:

  1. SELECT id,keyword,content,tags,device_serial,
  2. enable,display,projectid
  3. FROM tb_robot_answer_lib
  4. WHERE (projectid = 533840063904560 AND (device_serial = '123abcdasd123123a' OR device_serial = ''))

综上 细节很重要!

发表评论

表情:
评论列表 (有 0 条评论,89人围观)

还没有评论,来说两句吧...

相关阅读