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>


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM