Mybatis Plus帶多條件的多表聯合、分頁、排序查詢


聲明:本文系原創,轉載請注明出處。

注意:本程序使用SpringBoot+Mybatis Plus

一、現有表

student學生表:

id stuName stuAge graduateDate facultyId
1 盧1 21 2019-11-20 20:29:20 1
2 盧2 20 2019-11-27 20:29:40 2
3 盧3 22 2019-11-28 20:29:53 3
4 盧4 17 2019-11-28 20:30:20 2
5 盧5 17 2019-11-21 20:29:20 1
6 盧6 17 2025-12-11 20:29:20 3
7 盧7 20 2019-11-20 20:29:20 2
8 盧8 22 2019-11-27 20:29:40 3
9 盧9 17 2025-12-11 20:29:20 2
10 盧10 21 2019-11-28 20:30:20 1
11 盧11 17 2019-11-21 20:29:20 1
12 盧12 17 2019-11-11 20:29:20 3
13 盧13 17 2019-11-20 20:29:20 2
14 盧14 18 2025-12-11 20:29:20 3
15 盧15 22 2019-11-28 20:29:53 3
16 盧16 22 2019-11-28 20:30:20 1
17 盧17 18 2019-11-21 20:29:20 1
18 盧18 20 2025-12-11 20:29:20 2
19 盧19 21 2019-11-21 20:29:20 3
20 盧20 19 2025-12-11 20:29:20 3
21 盧21 18 2019-11-28 22:16:17 1

facultylist學院表:

id facultyName
1 計算機與通信工程學院
2 數學與統計學院
3 文法學院

二、同時滿足以下需求:

1.多表聯合查詢出學院名字

需求展示:學生表聯合學院表隱去學院id直接展示學院名給用戶:

id stuName stuAge graduateDate facultyName
1 盧1 21 2019-11-20 20:29:20 計算機與通信工程學院
2 盧2 20 2019-11-27 20:29:40 數學與統計學院
3 盧3 22 2019-11-28 20:29:53 文法學院
4 盧4 17 2019-11-28 20:30:20 數學與統計學院
5 盧5 17 2019-11-21 20:29:20 計算機與通信工程學院

2.可以帶多條件查詢

學生名字模糊搜索

年齡范圍搜索

搜索是否畢業

指定字段排序

3.指定頁碼,頁數據大小進行物理分頁查詢

三、解決步驟

今天找了一下午資料,終於可以同時滿足以上所有需求了!開干!

Spring Boot配置

重要配置已經做注釋!

server.port=9999
#設置jackson的時區和輸出形式
spring.jackson.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
#URL要設置數據庫編碼、時區、允許多語句查詢(等會會講原因)
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8&serverTimezone=GMT%2b8&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=6666
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#關閉字段名的映射(關閉如userName映射成user_name)
mybatis-plus.configuration.map-underscore-to-camel-case=false
#配置xml Mapper路徑
mybatis-plus.mapper-locations=classpath:mapping/*Mapper.xml

MP配置

創建一個MP的配置類寫入如下內容,主要是配置mapper路徑

package com.looyeagee.web.util;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
@Configuration
@MapperScan("com.looyeagee.web.mapper")
public class MybatisPlusConfig {

}

實體類編寫

Student.java

package com.looyeagee.web.bean;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Student implements Serializable {
    private Long id;
    private String stuName;
    private Integer stuAge;
    private Date graduateDate;
    private Long facultyId;
}

Select.java(把查詢條件封裝成類)

package com.looyeagee.web.bean;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.io.Serializable;

@Data
public class Select implements Serializable {
    String stuName;//模糊搜索學生名
    Integer minAge;//最小年齡 用Integer不用int是因為用戶可以不選擇此條件(null)即沒有最小年齡限制 用int默認值是0
    Integer maxAge;//最大年齡
    Boolean isGraduate;//是否畢業 為null就是不管畢業還是沒畢業都要
    Integer pageNumber;//第幾頁 從1開始
    Integer pageSize;//每頁幾個數據
    String orderBy;//排序字段
    Boolean highToLow;//是否降序 為false和null就是升序 為true就是降序
}

Result.java(把結果也封裝)

package com.looyeagee.web.bean;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)//為null的字段 不輸出到前端 看以下的stuAge字段
public class Result implements Serializable {
    private Long id;
    private String stuName;
    private Integer stuAge;//為什么要用Integer而不是int 因為int會有默認值0,而Integer默認是null,如果查到年齡為null就會顯示為0歲了,這樣輸出到前端就是0歲,而我們不期望前端展示為null的數據
    private Date graduateDate;
    private String facultyName;
}

StudentMapper.xml編寫

前提知識:

mysql如何通過當前頁碼和頁數據條數分頁?

mysql limit m,n是mysql分頁用的語句,不過此處的m不是當前頁碼而是從第幾條數據開始,n是取幾條數據。所以假設PageNumber為第幾頁,PageSize為一頁數據條數,則寫法為limit (PageNumber-1)*PageSize,PageSize

如何用mysql limit分頁查詢的同時返回符合條件數據總數以確定總頁數?

用上面的方法雖然能分頁,但是沒有查出符合條件總個數,所以就不知道數據總共有多少頁數。MP內部分頁的實現是先查詢符合條件的個數再用limit查詢,不過這樣會導致兩次查詢浪費資源,而且要寫2個條件一模一樣的select查詢,很不方便,這里有個解決方案可以一次性返回數據和總條數:通過SQL_CALC_FOUND_ROWS和SELECT FOUND_ROWS();來獲取。
為了說的更清楚,我直接貼出測試sql:我的21個數據中名字含有字符"2"的有4個同學,我想每頁展示2條數據,並且訪問第1頁:根據我貼出的數據,滿足條件的有4個,id分別為2,12,20,21。因為1頁只展示2個數據,所以第1頁應該是返回2,12這兩個數據。語句

SELECT SQL_CALC_FOUND_ROWS * FROM `student` WHERE stuName LIKE '%2%' limit 0,2;SELECT FOUND_ROWS();

執行后一次性返回2個結果集(這就是前面要配置一次性可執行多個語句的原因,默認不可以一次性執行多個語句),如圖:
2019-11-28_22-39.png

2019-11-28_22-40.png

第二個結果集就是總條數。下面介紹Mapper的配置。

2個結果集的配置:

<resultMap id="ResultMap" type="com.looyeagee.web.bean.Result"/>
<resultMap id="RecordsCount" type="integer"/>

resultMap標簽是mapper的子標簽用來指定結果集的id和類型。由於返回的第一個結果集的結果為我們定義的實體類Result,所以類型填寫完整實體類路徑;由於返回的第二個結果集的結果為一個整數,所以類型是integer。

  <select id="findResultByInfo" resultMap="ResultMap,RecordsCount"
            parameterType="com.looyeagee.web.bean.Select" resultType="java.util.List">

在select標簽中添加resultMap屬性來指定結果集的id,由於這個select會返回2個結果集,所以resultMap屬性填寫2個剛剛定義的結果集id,用英文逗號隔開。parameterType屬性就是我們封裝的查詢實體類。返回的結果類型是List。

下面貼出完整多條件查詢代碼:
注意:
1.大於號小於號要用xml實體字符轉義。
2.orderby字段的使用要用${},不讓程序自動預編譯。
3.排序多加一個通過id升序,因為mysql排序是不穩定的,可能會出現不同頁數出現相同數據的情況。
4.此處傳進去的pageNumber已經經過了PageNumber=(PageNumber-1)*PageSize的處理。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.looyeagee.web.mapper.StudentMapper">
    <resultMap id="ResultMap" type="com.looyeagee.web.bean.Result"/>
    <resultMap id="RecordsCount" type="integer"/>
    <select id="findResultByInfo" resultMap="ResultMap,RecordsCount"
            parameterType="com.looyeagee.web.bean.Select" resultType="java.util.List">
        SELECT SQL_CALC_FOUND_ROWS
        `student`.`id` AS `id`,
        `student`.`stuName` AS `stuName`,
        `student`.`stuAge` AS `stuAge`,
        `student`.`graduateDate` AS `graduateDate`,
        `facultylist`.`facultyName` AS `facultyName`
        FROM
        ( `facultylist` JOIN `student` )
        WHERE
        (
        `facultylist`.`id` = `student`.`facultyId`)
        -- 標題模糊搜索
        <if test="stuName != null">
            AND `student`.`stuName` LIKE CONCAT('%',#{stuName},'%')
        </if>
        -- &gt;=是大於等於
        <if test="minAge!=null">
            AND `student`.`stuAge`&gt;= #{minAge}
        </if>
        -- &lt;=是小於等於
        <if test="maxAge!=null">
            AND `student`.`stuAge` &lt;= #{maxAge}
        </if>

        -- 沒畢業 畢業時間大於現在
        <if test="isGraduate  != null and isGraduate ==false">
            AND `student`.`graduateDate`&gt;=NOW()
        </if>

        -- 畢業了 畢業時間小於現在
        <if test="isGraduate  != null and isGraduate ==true">
            AND `student`.`graduateDate`&lt;=NOW()
        </if>
        <if test="orderBy!=null and orderBy!=''">

            <if test="highToLow ==null or highToLow ==false">
                ORDER BY ${orderBy} ASC,`student`.`id` ASC -- 加id ASC是為了保證分頁結果的唯一性 mysql排序是不穩定的 https://www.jianshu.com/p/1e8a19738ae4
            </if>
            <if test="highToLow !=null and highToLow ==true">
                ORDER BY ${orderBy} DESC,`student`.`id` ASC
            </if>
        </if>
        -- 分頁查詢
        LIMIT
        #{pageNumber},#{pageSize};
        -- 接着查詢符合條件個數
        SELECT FOUND_ROWS();
    </select>
</mapper>

StudentMapper類編寫

注意返回類型即可。

package com.looyeagee.web.mapper;


import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.looyeagee.web.bean.Select;
import com.looyeagee.web.bean.Student;

import java.util.List;


public interface StudentMapper extends BaseMapper<Student> {
    List<List<?>> findResultByInfo(Select select);
}

測試類編寫

關於總頁數計算的說明:總數據條數除以每頁數據條數,如果沒有余數,結果就是總頁數;如果有余數,則要將計算結果+1(進1法);用一句話就是(totalCount + pageSize - 1) / pageSize

package com.looyeagee.web;

import com.looyeagee.web.bean.Result;
import com.looyeagee.web.bean.Select;
import com.looyeagee.web.mapper.StudentMapper;
import com.looyeagee.web.service.impl.StudentServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class WebApplicationTests {

    @Autowired
    StudentMapper studentMapper;

    @Test
    void selectTest() {
        Select selectInfo = new Select();
        int nowPageIndex = 1;
        int pageSize = 5;
        selectInfo.setPageNumber((nowPageIndex - 1) * pageSize);
        selectInfo.setPageSize(pageSize);
        selectInfo.setOrderBy("stuAge");
        selectInfo.setHighToLow(true);
        selectInfo.setIsGraduate(true);
        selectInfo.setMinAge(17);
        selectInfo.setMaxAge(20);
        List<List<?>> findtest = studentMapper.findResultByInfo(selectInfo);
        List<Result> orderinfos = (List<Result>) findtest.get(0);
        int totalCount = (Integer) findtest.get(1).get(0);
        System.out.println("當前頁面記錄數:" + orderinfos.size());
        System.out.println("符合條件記錄數:" + totalCount);
        System.out.println("當前頁數:" +nowPageIndex);
        System.out.println("總頁數:" + ((totalCount + pageSize - 1) / pageSize));
        orderinfos.forEach(System.out::println);
    }


}

以上的測試是篩選在我們的21個數據中,最小年齡17,最大年齡20,已經畢業(畢業時間小於現在時間),總共結果是有9個同學:通過年齡降序分別為2,7,17,21,4,5,11,12,13號,
選擇第1頁,1頁5個數據,輸出結果

當前頁面記錄數:5
符合條件記錄數:9
當前頁數:1
總頁數:2
Result(id=2, stuName=盧2, stuAge=20, graduateDate=Wed Nov 27 20:29:40 CST 2019, facultyName=數學與統計學院)
Result(id=7, stuName=盧7, stuAge=20, graduateDate=Wed Nov 20 20:29:20 CST 2019, facultyName=數學與統計學院)
Result(id=17, stuName=盧17, stuAge=18, graduateDate=Thu Nov 21 20:29:20 CST 2019, facultyName=計算機與通信工程學院)
Result(id=21, stuName=盧21, stuAge=18, graduateDate=Thu Nov 28 22:16:17 CST 2019, facultyName=計算機與通信工程學院)
Result(id=4, stuName=盧4, stuAge=17, graduateDate=Thu Nov 28 20:30:20 CST 2019, facultyName=數學與統計學院)

nowPageIndex改為2,輸出第二頁結果(剩余4個數據):

當前頁面記錄數:4
符合條件記錄數:9
當前頁數:2
總頁數:2
Result(id=5, stuName=盧5, stuAge=17, graduateDate=Thu Nov 21 20:29:20 CST 2019, facultyName=計算機與通信工程學院)
Result(id=11, stuName=盧11, stuAge=17, graduateDate=Thu Nov 21 20:29:20 CST 2019, facultyName=計算機與通信工程學院)
Result(id=12, stuName=盧12, stuAge=17, graduateDate=Mon Nov 11 20:29:20 CST 2019, facultyName=文法學院)
Result(id=13, stuName=盧13, stuAge=17, graduateDate=Wed Nov 20 20:29:20 CST 2019, facultyName=數學與統計學院)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM