Mybatis学习笔记(四)【常用查询】

一、模糊查询


1.创建对象

Student类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {

    private int id;     //学生id
    private String name;    //学生姓名

    //需要关联的一个老师
    private Teacher teacher;
    
}

Teacher类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher implements Serializable {

    private int id;     // 老师id
    private String name;    // 老师姓名

    //一个老师拥有多个学生
    private List<Student> students;
}

2.编写接口

StudentMapper接口


public interface StudentMapper {

    //根据姓名模糊查询  (这个才是这部分的要点,下面的是一些基础方法)
    List<Student> getStudentsByName(@Param("name") String name);

/*
    //获取所有学生信息
    List<Student> getAllStudents();

    //根据id查询学生信息
    Student getStudentById(@Param("id") Integer id);

    //增加一个学生
    int addStudent(Student student);

    //更新一个学生信息
    int updateStudent(Student student);

    //根据id删除一个学生信息
    int deleteStudent(@Param("id") Integer id);
    
*/

}

TeacherMapper接口


public interface TeacherMapper {

    //获取所有老师信息
    List<Teacher> getAllTeacher();

    //根据id查询老师信息
    Teacher getTeacherById(@Param("id") Integer id);

    //增加一个老师信息
    int addTeacher(Teacher Teacher);

    //更新一个老师信息
    int updateTeacher(Teacher Teacher);

    //根据id删除一个老师信息
    int deleteTeacher(@Param("id") Integer id);

}

3.配置对应XML文件

只用配置Student类的接口映射文件即可


<?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.vinjcent.dao.StudentMapper">


    <!--  普通模糊查询  -->
    <select id="getStudentsByName" parameterType="String" resultType="Student">
        select * from student where name like #{name}
    </select>


</mapper>

4.测试

测试一

    @Test
    public void testgetStudentsByName(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        //这里需要传递类型为String的参数
        List<Student> students = studentMapper.getStudentsByName("Totoro");

        //输出查询结果
        students.forEach(System.out::println);

        sqlSession.close();

    }

结果
在这里插入图片描述

测试二

在对应XML文件中修改SQL语句


    <!--  使用%查询  -->
    <select id="getStudentsByName" parameterType="String" resultType="Student">
        select * from student where name like '%'#{name}'%'
    </select>
    

结果
在这里插入图片描述

测试三(推荐)

同样在对应XML中修改,使用MySQL中的concat()函数


    <!--  使用MySQL中的concat()函数  -->
    <select id="getStudentsByName" parameterType="String" resultType="Student">
        select * from student where name like concat('%',#{name},'%')
    </select>
    

结果

在这里插入图片描述

二、联表查询


1. 多对一处理(多个Student对象,对应一个Teacher对象)

可以从上面看到,每次查询出来的结果Student类中的teacher属性都为null,这里我们通过对应接口的XML文件中的标签association来查询

1)编写StudentMapper接口

将上面的StudentMapper注释打开即可

2)在XML文件中映射接口方法

当在 ResultMap 中决定使用哪种类型处理器时,此时 Java 类型是已知的(从结果类型中获得),但是 JDBC 类型是未知的。 因此 Mybatis 使用 javaType=[Java 类型], jdbcType=null 的组合来选择一个类型处理器

注意】这里的 select 语句中的结果必须指定 resultMap 而不是 resultType

<!--
        id(resultMap中):当前文件中resultMap的唯一标识
        type:我们的javaType
        result:返回的属性字段  //property ===> java实体类中的属性字段
                              //column ===> 数据库查询对应的字段

        复杂的属性,我们需要单独处理
        对象: association
        javaType: 在java中的类型
        select: 引用当前文件中,标签为select的唯一标识

    -->
    <resultMap id="StudentAndTeacher" type="Student">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacherById"/>
    </resultMap>

    <select id="getTeacherById" resultType="Teacher">
        select * from teacher where id = #{id}
    </select>

	<!--  resultMap结果集映射  -->
    <select id="getAllStudents" resultMap="StudentAndTeacher">
        select * from student
    </select>

3)测试

这里我们使用查询全部学生的方法getAllStudents()


    @Test
    public void testgetAllStudents(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        //
        List<Student> students = studentMapper.getAllStudents();

        //输出查询结果
        students.forEach(System.out::println);

        sqlSession.close();

    }
    

结果
在这里插入图片描述

2. 一对多处理(一个Teacher对象,对应多个Student对象)

看完刚刚的多对一,可以知道Teacher类中有一个属性为List的泛型集合,当我们想查询完整时,又如何去做呢?

1)编写TeacherMapper接口

上面已经写过了,就不重复写了

2)在XML文件中映射接口方法

千万要注意这里的子查询!!!


    <!--
            这里并没有错,在我们结果集映射时,传递的参数Param("id")是老师的id
            查出结果后,我们再用老师的id作为collection标签中的column属性的值
            而这里的#{id}也就是老师的id,student表中有tid(老师id)字段
      -->
    <select id="getStudentByTeacherId" resultType="Student">
        select * from student where  tid = #{id}
    </select>
    

完整XML映射文件


    <!--
        集合:collection
        javaType:指定属性的类型
        集合中的泛型信息,我们使用ofType
        collection标签中的column是数据库对应表的字段,因为是根据teacher表查询的,所以这里column对应的是teacher表中的id
    -->

    <resultMap id="TeacherAndStudents" type="Teacher">
        <result property="id" column="id"/>
        <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentsByTeacherId" column="id">
        </collection>
    </resultMap>

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

    <select id="getTeacherById" resultMap="TeacherAndStudents">
        select * from teacher where id = #{id}
    </select>
    

3)测试


    @Test
    public void testgetTeacherById(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();

        TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);

        Teacher teacher = teacherMapper.getTeacherById(1);

        //输出查询结果
        System.out.println(teacher);

        sqlSession.close();

    }
    

结果
在这里插入图片描述

3. 注意点

  • 保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多和多对一中,属性名和字段名的问题
  • 如果问题不好排查错误,可以使用日志,建议使用log4j(在我的《Mybatis学习笔记(三)》)有提到

三、结果嵌套和查询嵌套


为了让大家更加能够区分结果嵌套查询嵌套的区别,我们重新建几个类演示一下

数据库设计

(1)三张表(Student、Subject、Sheet)

# 学生表
CREATE TABLE `student` (
  `id` INT(4) NOT NULL COMMENT '学生ID',
  `name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
  `age` INT(3) NOT NULL DEFAULT '0' COMMENT '年龄',
  `sex` VARCHAR(2) NOT NULL DEFAULT '未知' COMMENT '性别',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

# 课程表
CREATE TABLE `subject` (
  `id` INT(4) NOT NULL COMMENT '课程ID',
  `name` VARCHAR(30) NOT NULL COMMENT '课程名',
  `average` DOUBLE DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

# 成绩表
CREATE TABLE `sheet` (
  `studentId` INT(4) NOT NULL COMMENT '学生ID',
  `subjectId` INT(4) NOT NULL COMMENT '课程ID',
  `score` DOUBLE DEFAULT NULL COMMENT '分数',
  KEY `studentId` (`studentId`),
  KEY `subjectId` (`subjectId`),
  CONSTRAINT `sheet_ibfk_1` FOREIGN KEY (`studentId`) REFERENCES `student` (`id`),
  CONSTRAINT `sheet_ibfk_2` FOREIGN KEY (`subjectId`) REFERENCES `subject` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

(2)对应实体类

//学生类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {

    /**
     * 学生ID
     */

    private Integer id;

    /**
     * 姓名
     */

    private String name;

    /**
     * 年龄
     */

    private int age;

    /**
     * 性别
     */

    private String sex;

}
//课程类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Subject implements Serializable {

    /**
     * 课程ID
     */

    private Integer id;

    /**
     * 课程名
     */

    private String name;

    /**
     * 平均成绩
     */
    private double average;


}


//成绩类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Sheet implements Serializable {

    /**
     * 学生ID
     */

    private Student student;

    /**
     * 课程ID
     */

    private Subject subject;

    /**
     * 分数
     */
    private Double score;


}

(3)Mapper接口

这里我们只写成绩类的接口SheetMapper即可


public interface SheetMapper {

    // 根据模糊 + 条件,查询学生的成绩  方式一:查询嵌套
    List<Sheet> getStudentsByConditions1(Map<String,Object> map);

    // 根据模糊 + 条件,查询学生的成绩  方式二:结果嵌套
    List<Sheet> getStudentsByConditions2(Map<String,Object> map);



}

(4)对应XML文件

也是只用写一个SheetMapper.xml


<?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.vinjcent.dao.SheetMapper">
    

    <!--根据id查询学生-->
    <select id="getStudentById" resultType="Student">
        select * from student
        where id = #{id}
    </select>

    <!--根据id查询课程-->
    <select id="getSubjectById" resultType="Subject">
        select * from subject
        where id = #{id}
    </select>

    <resultMap id="Query_nesting" type="Sheet">
        <association property="student" column="studentId" javaType="Student" select="getStudentById">
        </association>
        <association property="subject" column="subjectId" javaType="Subject" select="getSubjectById">
        </association>
    </resultMap>

    <!--查询学生的成绩  方式一:查询嵌套-->
    <select id="getStudentsByConditions1" resultMap="Query_nesting" parameterType="map">
        select * from sheet
    </select>

<!--=====================================================================-->

    
    <!--查询学生的成绩  方式二:结果嵌套-->
    <resultMap id="Result_nesting" type="Sheet">
        <result property="student.id" column="stuId"/>
        <result property="student.name" column="stuName"/>
        <result property="subject.name" column="subName"/>
        <result property="score" column="score"/>
    </resultMap>

    <select id="getStudentsByConditions2" resultMap="Result_nesting" parameterType="map">
        select 
        	stu.id stuId,
        	stu.name stuName,
        	sub.name subName,
        	score
        from student stu
	        right join sheet s 
	        	on stu.id = s.studentId
	        inner join subject sub 
	        	on s.subjectId = sub.id
    </select>
</mapper>

1. 结果嵌套处理

在XML文件中,我们上半部分就是结果嵌套处理的代码,因为在设计数据库时,成绩表Sheet就三个字段
在这里插入图片描述
而在成绩表实体类Sheet中,它有两个属性是对象,所以要进行两次子查询
原理就是在数据库中先查Sheet类,再根据数据库表Sheet的两个字段进行子查询
在这里插入图片描述

2. 查询嵌套处理

当然,对应的XML下半段就是我们的查询嵌套,我们先来看看这段sql语句查询了什么

select 
	stu.id stuId,
	stu.name stuName,
	sub.name subName,
	score
from student stu
	right join sheet s 
		on stu.id = s.studentId
	inner join subject sub 
		on s.subjectId = sub.id

结果
在这里插入图片描述
这里的查询是将3个表中指定字段的内容挑选出来,也就是我们想要得到的数据,由于挑选出来的数据并不都在一个表中,我们要对查询出来的结果进行映射到Sheet类中属性为对象中的属性中(有点拗口),然后才结束查询,我们来看看具体过程
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

结论

从这两种方式的查询来看,SQL语句代码量结果嵌套可能会更多点,但是,但也很明确地一步一步进行查询,从外到里。而查询嵌套更注重于对SQL语句掌握的基础,直接进行数据库的联表查询,查询我们想要的指定内容

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Naijia_OvO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值