The use of and and or in MybatisPlus & the problem of priority of and and or encountered by MybatisPlus

The use of and and or in MybatisPlus

need

Recently, I found that MyBatisPlus is quite easy to use, but I suddenly found that it is also an advantage for a persistence layer framework to support splicing complex SQL. For a persistence layer framework splicing SQL, or is more difficult than and, so here Use cases to realize the simple use of or and and in MybatisPlus.

The use of and and or in MybatisPlus_spring boot

The use of and and or

Case 1: A and B

@GetMapping("/AandB")
    public Object AandB(){
    
    
        //SELECT id,name,age,sex FROM student WHERE (name = ? AND age = ?)
        List<Student> list = studentService.lambdaQuery().eq(Student::getName, "1").eq(Student::getAge, 1).list();
        return list;
    }

Case 2: AorB

 @GetMapping("/AorB")
    public Object AorB(){
    
    
        //SELECT id,name,age,sex FROM student WHERE (name = ? OR age = ?)
        List<Student> list = studentService.lambdaQuery().eq(Student::getName, "1").or().eq(Student::getAge, 12).list();
        return list;
    }

案例3:A or(C and D)

@GetMapping("/A_or_CandD")
    public Object A_or_CandD() {
    
    
        //SELECT id,name,age,sex FROM student WHERE (name = ? OR (name = ? AND age = ?)) 
      List<Student> list =
          studentService
              .lambdaQuery()
              .eq(Student::getName, "1")
              .or(wp -> wp.eq(Student::getName, "1").eq(Student::getAge, 12))
              .list();
      return list;

Case 4: (AandB)or(CandD)

@GetMapping("/AandB_or_CandD")
  public Object AandB_or_CandD() {
    
    
    // SELECT id,name,age,sex FROM student WHERE ((name = ? AND age = ?) OR (name = ? AND age = ?)) 
    List<Student> list =
        studentService
            .lambdaQuery()
            .and(wp -> wp.eq(Student::getName, "1").eq(Student::getAge, 12))
            .or(wp -> wp.eq(Student::getName, "1").eq(Student::getAge, 12))
            .list();
    return list;
  }

案例5:A or (B and ( C or D))

@GetMapping("/complex")
  public Object complex() {
    
    
    // SELECT * FROM student WHERE ((name <> 1) OR (name = 1 AND (age IS NULL OR age >= 11)))
    List<Student> list =
        studentService
            .lambdaQuery()
            .and(wp -> wp.ne(Student::getName, "1"))
            .or(
                wp ->
                    wp.eq(Student::getName, "1")
                        .and(wpp -> wpp.isNull(Student::getAge).or().ge(Student::getAge, 11)))
            .list();
    return list;
  }

Summarize

1 You can let him print the SQL statement, so you know the SQL you know

2 The situation I encountered is that no error is reported and SQL is not printed, so it can only be DEBUG

3 Handwritten SQL is also available in mapper



Introduction to the use and principle of and() and or() in Mybatis-Plus

1. Simple non-priority connection (that is, sql statement without brackets)

To put it simply, the default and connection between two sub-conditions, if the or () is explicitly written between the two sub-conditions, or or connection.

  1. connected with and()

When it is necessary to simply connect two conditions with, the most direct way to write is:

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

Of course, it is also possible to explicitly write and() as follows, but it is not necessary:

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

When it is necessary to simply or connect two conditions, the most direct way to write is:

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

Of course it can also be as follows, but it is not so intuitive:

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

2. Complex prioritized connections

There are two not recommended practices above, because the sql statement is a simple connection such as A or B, A and B. When it comes to complex priority connections such as A and ( B or C) and D, Direct splicing will result in A and B or C and D. So at this time, you need or (Consumer consumer), and (Consumer consumer). The examples are as follows:

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

The generated sql statement is as follows:

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

It can also be seen that when the two method parameters of or(Consumer consumer) and and(Consumer consumer) are Consumer, 2 pairs of parentheses will be generated at the connection to increase the priority.



The problem of and and or priority encountered by mybatisplus

During the test, I found that when I got the data information, I got unexpected data

Viewed Mybatis query statement:

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

The original intention is to want all the data under the projectId, the DeviceSerial is "" or "input".

Observe that the sql it generates is as follows:

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

search result:
img

You can see that there is a lot of data that is not what you want.

The root cause of the problem lies in the priority of this AND and OR. The priority of relational operators from high to low is: NOT > AND > OR

So in fact, the order of execution is to first judge
projectid = 533840063904560 AND device_serial = '123abcdasd123123a'
and then judge device_serial = '', so there is the above result.

It is also simple to change, you need to combine the two conditions around or into one (). The specific code corrections are as follows:

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

The sql generated like this:

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

The details are important!

Guess you like

Origin blog.csdn.net/qq_43842093/article/details/130311753