1. 程式人生 > 實用技巧 >03-Mybatis之分頁查詢和多表聯合查詢

03-Mybatis之分頁查詢和多表聯合查詢

分頁查詢和多表聯合查詢

1.分頁查詢

普通查詢

<select id="selectAll" resultType="User" >
    select * from user
</select>

分頁查詢基礎:使用sql的limit關鍵字進行分頁查詢

缺陷:並不是所有資料庫都使用limit進行分頁查詢的,因此這條語句不通用

SELECT * FROM table LIMIT [offset,] rows---->從第offset開始查詢出rows條資料

<select id="selectAll" resultType="User" >
    select * from user LIMIT [offset,] rows
</select>

利用RowBounds實現通用分頁

//在普通查詢的基礎上,改變java中的語句(呼叫Mapper部分做一些修改)
RowBounds rowBounds=new RowBounds(offset,rows);
User user = session.selectList("com.whether.mapper.UserMapper.findAll",null,rowBounds);

使用分頁外掛pageHelper(不推薦)

https://pagehelper.github.io/docs/howtouse/

2.多表聯合查詢

多對一、一對多(不需要中間表)

一.建立表

//建立Teacher表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher`  (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

INSERT INTO `teacher` VALUES (1, '趙老師');
INSERT INTO `teacher` VALUES (2, '劉老師');

SET FOREIGN_KEY_CHECKS = 1;
//建立Student表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`  (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `tid` int(10) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `tid`(`tid`) USING BTREE,
  CONSTRAINT `student_ibfk_1` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

INSERT INTO `student` VALUES (1, '小明', 1);
INSERT INTO `student` VALUES (2, '小紅', 1);
INSERT INTO `student` VALUES (3, '小王', 1);
INSERT INTO `student` VALUES (4, '小張', 2);
INSERT INTO `student` VALUES (5, '小李', 2);
INSERT INTO `student` VALUES (6, '小秦', 1);

SET FOREIGN_KEY_CHECKS = 1;

二.建立實體類Student/Teacher---每一個學生都有一個老師,這裡關注學生

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private int id;
    private String name;
    //學生需要關聯一個老師
    private Teacher teacher;
}
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Teacher {
    private int id;
    private String name;
}

三.編寫Mapper

多對一(多個學生對應一個老師,查詢結果與一對一相似)
public interface StudentMapper {
    //查詢所有學生資訊,以及對應的老師資訊---聯表查詢
    List<Student> finAllStudent();
    //查詢所有學生資訊,以及對應的老師資訊---巢狀查詢(子查詢)
    List<Student> finAllStudent2();
}
巢狀查詢(子查詢---推薦使用)

實際上這是兩個查詢,在第一個查詢的基礎上,再進行一次查詢,將第二次查詢的結果注入到某一部分比如下面的案例,先查詢所有的學生,然後根據查詢到的tid列,再次進行教師資訊查詢,將這兩部分查詢到的資訊對映到Student,其實就是在第一個查詢的基礎上,再進行第二個查詢,將第二個查詢的結果插入到某一個欄位中進行輸出

<!--先查詢學生資訊,在查出來後再根據查出來的tid查詢老師資訊-->
<select id="finAllStudent2" resultMap="StudentAndTeacher2">
    select * from student
</select>
<resultMap id="StudentAndTeacher2" type="Student">
    <!--
        property:對映到列結果的欄位或屬性(對應的實體類的屬性)。
        column:sql語句查詢出來的資料庫中的列名,或者是列的別名
        javaType:一個Java類的全限定名(使用別名後可以使用別名)
        select:用於載入複雜型別屬性的對映語句的ID,它會從column屬性中指定的列檢索資料,作為引數傳遞給此select語句
        -->
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <!--複雜物件需要單獨處理
            物件:使用association標籤
            集合:使用collection標籤
        -->
    <!--處理一個複雜結果,複雜結果將會作為Teacher型別對映給Student的teacher屬性,依據查詢到的tid這一列-->
    <!--如果查詢的sql語句需要傳入多個引數,使用鍵值對的形式進行傳入,實際上是傳入一個map-->
    <association property="teacher" column="{tid=tid}" javaType="Teacher" select="findTeacherById"/>
</resultMap>

<select id="findTeacherById" resultType="Teacher">
    select * from teacher WHERE id=#{id}
</select>
聯表查詢
<!--
	這條sql語句的結果是以sid,sname,tid,tname為列的一個表
    通過resultMap將查詢到的欄位對映到配置的resultMap
-->
<select id="finAllStudent" resultMap="StudentAndTeacher">
    select s.id sid,s.name sname,s.tid tid,t.name tname
    from student s left join teacher t on s.tid=t.id
</select>
<!--返回結果(type)是Student-->
<resultMap id="StudentAndTeacher" type="Student">
    <!--把查詢出來的sid對映給Student的id屬性-->
    <result property="id" column="sid"/>
    <!--把查詢出來的sname對映給Student的name屬性-->
    <result property="name" column="sname"/>
    <!--處理一個複雜結果,複雜結果將會作為Teacher型別對映給Student的teacher屬性-->
    <association property="teacher" javaType="Teacher">
        <!--把查詢出來的tid對映給Teacher的id屬性-->
        <result property="id" column="tid"/>
        <!--把查詢出來的tname對映給Teacher的name屬性-->
        <result property="name" column="tname"/>
    </association>
</resultMap>
一對多(一個老師對應多個學生,這裡關注老師)
實體類修改
public class Teacher {
    private int id;
    private String name;
    //一個老師對應多個學生
    private List<Student> students;
}
public class Student {
    private int id;
    private String name;
    private int tid;
}
public interface TeacherMapper {
    Teacher findTeacherById(@Param("tid") int id);
    Teacher findTeacherById2(@Param("tid") int id);
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.whether.mapper.TeacherMapper">
    <!--聯表查詢-->
    <select id="findTeacherById" resultMap="TeacherAndStudent">
        select s.id sid,s.name sname,t.id tid,t.name tname
        from student s,teacher t
        WHERE s.tid=t.id and t.id=#{tid}
    </select>
    <resultMap id="TeacherAndStudent" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!--結果為List,使用collection標籤-->
        <!--ofType泛型裡面的型別-->
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>
    <!--巢狀查詢(子查詢)-->
    <select id="findTeacherById2" resultMap="TeacherAndStudent2">
        select * from teacher WHERE id=#{tid}
    </select>

    <resultMap id="TeacherAndStudent2" type="Teacher">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <collection property="students" javaType="ArrayList" ofType="Student" select="findStudentById" column="{id=id}"/>
    </resultMap>

    <select id="findStudentById" resultType="Student">
        select * from student where tid=#{id}
    </select>
</mapper>

多對多(需要中間表)

下面是一個部落格查詢的案例,每一篇文章有一個或者多個標籤,同時一個標籤有一篇或者多篇文章

文章表content中包含了文章id、文章內容......,中間表content_meta包含了文章id,對應的標籤id,標籤表metas包含了標籤id、標籤名

查詢過程:先查詢所有的文章,然後根據查詢出來的文章id,去中間表查詢出標籤的id,再根據標籤的id找出對應標籤名

<resultMap id="ContentDto" type="com.whether.dto.ContentDto">
    <result property="cid" column="cid"/>
    <!--其他值按照預設值進行注入,標籤根據getTags獲取-->
    <collection property="tags" javaType="ArrayList" ofType="String" select="getTags" column="{cid=cid}"/>
</resultMap>
<!--獲取標籤List-->
<!--根據文章的id,查詢出標籤id,再根據標籤的id找出對應標籤名-->
<select id="getTags" resultType="String">
    select m.name from content_meta cm,metas m WHERE cm.mid=m.mid AND m.type='tag' AND cm.cid=#{cid}
</select>
<!-- 查詢所有文章資訊 -->
<select id="findAll" resultMap="ContentDto">
    SELECT * FROM content
</select>