【Spring】— 动态SQL :MyBatis的关联映射

news2025/2/11 6:18:50

目录

    • MyBatis的关联映射
      • 1、关联关系概述
      • 2、MyBatis中的关联关系
        • 2.1 一对一
        • 2.2 一对多
        • 2.3 多对多

MyBatis的关联映射

在实际应用中,对数据库的操作会涉及多张表,这在面向对象中就涉及对象与对象之间的关联关系。针对多表之间的操作,MyBatis提供了关联映射,通过关联映射来处理对象与对象之间的关联关系。

1、关联关系概述

在关系型数据库中,多表之间存在3种关联关系,分别为一对一、一对多和多对多。

  • 一对一:在任意一方引入对方主键作为外键。
  • 一对多:在“多”的一方添加“一”的一方的主键作为外键。
  • 多对多:产生中间关系表,引入两张表的主键作为外键,两个主键成为联合主键或使用新的字段作为主键。

对象之间也存在3种关联关系。

  • 一对一的关系:在本类中定义对方类型的对象,比如A类中定义B类类型的属性b、在B类中定义A类类型的属性a。
  • 一对多的关系:一个A类类型对应多个B类类型的情况,需要在A类中以集合的方式引入B类类型的对象,在B类中定义A类类型的属性a。
  • 多对多的关系:在A类中定义B类类型的集合,在B类中定义A类类型的集合。

2、MyBatis中的关联关系

2.1 一对一

在现实生活中,一对一关联关系是十分常见的。例如,一个学生只有一本学生证,同时一本学生证也只对应一个学生。

那么MyBatis是怎么处理这种一对一关联关系的呢,之前学习的<resultMap>元素中包含一个<association>子元素,MyBatis就是通过该元素来处理一对一关联关系的。

<association>元素中,通常可以配置以下属性。

  • property:指定映射到的实体类对象属性,与表字段一一对应。
  • column:指定表中对应的字段。
  • javaType:指定映射到实体对象属性的类型。
  • select:指定引入嵌套查询的子SQL语句,用于关联映射中的嵌套查询。
  • fetchType:指定在关联查询时是否启用延迟加载,有lazy和eager两个属性值,默认值为lazy(默认关联映射延迟加载)。

<association>元素有如下两种配置方式。

在这里插入图片描述

注意
MyBatis在映射文件中加载关联关系对象主要通过两种方式:嵌套查询嵌套结果

嵌套查询是指通过执行另一条SQL映射语句来返回预期的复杂类型;
嵌套结果是使用嵌套结果映射来处理重复的联合结果的子集。

【示例9】接下来以学生和学生证之间的一对一关联关系为例。

查询学生及其关联的学生证信息是先通过查询学生表中的主键来获取学生信息,然后通过表中的外键来获取学生证表中的学生证号信息。其具体实现步骤如下。

步骤01 创建数据表。在db_mybatis数据库中分别创建名为tb_studentidcard和tb_student的数据表,同时预先插入几条数据。其执行的SQL语句如下所示。

#使用数据库db mybatis
USE db_mybatis;
#创建一个名称为tb_studentidcard的表
CREATE TABLE IF NOT EXISTS tb_studentidcard( 
		id INT PRIMARY KEY AUTO_INCREMENT,
		CODE VARCHAR(8)
);
#插入两条数据
INSERT INTO tb_studentidcard(CODE) VALUES('18030128');
INSERT INTO tb_studentidcard(CODE) VALUES('18030135');
#创建一个名称为tb_student的表(暂时添加少量字段)
CREATE TABLE tb_student(
	id INT PRIMARY KEY AUTO_INCREMENT,
	name VARCHAR(32),
	sex CHAR(1),
	card_id INT UNIQUE,
	FOREIGN KEY (card_id) REFERENCES tb_studentidcard(id)
);
#插入两条数据
INSERT INTO tb_student (name,sex,card_id) VALUES ('limin','f',1);
INSERT INTO tb_student (name,sex,card_id) VALUES ('jack','m',2);

步骤02 创建一个名为chapter09的Web项目,然后引入相关JAR包、MybatisUtils工具类以及mybatis-config.xml核心配置文件。

步骤03 在项目的com.ssm.po包下创建持久化类:学生证类StudentIdCard和学生类Student。

//StudentIdCard.java

package com.ssm.po;

/**
 * 功能描述
 *
 * @author: 衍生星球
 * @date: 2023年06月08日 17:40
 */

public class StudentIdCard {
    private Integer id;
    private String code;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    @Override
    public String toString() {
        return "StudentIdCard [id=" + id + ", code= " + code + "]";
    }
}
//Student.java

package com.ssm.po;

/**
 * 功能描述
 *
 * @author: 衍生星球
 * @date: 2023年06月08日 17:41
 */

public class Student {
    private Integer id;
    private String name;
    private String sex;
    private StudentIdCard studentIdCard;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public StudentIdCard getStudentIdCard() {
        return studentIdCard;
    }

    public void setStudentIdCard(StudentIdCard studentIdCard) {
        this.studentIdCard = studentIdCard;
    }

    @Override
    public String toString() {
        return "Student[id=" + id + ", name=" + name + ", sex=" + sex + ", studentIdCard=" + studentIdCard +"]";
    }
}

步骤04 在com.ssm.mapper包中创建学生证映射文件StudentIdCardMapper.xml和学生映射文件StudentMapper.xml,并在两个映射文件中编写一对一关联映射查询的配置信息。

StudentIdCardMapper.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.ssm.mapper.StudentIdCardMapper">
<!--    根据学生id获取学生证信息-->
    <select id="findStudentIdCardById" parameterType="com.ssm.po.StudentIdCard" resultType="com.ssm.po.StudentIdCard">
        select * from tb_studentidcard where id = #{id}
    </select>

</mapper>
StudentMapper.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.ssm.mapper.StudentMapper">
    <!--    根据学生id获取学生证信息-->
    <select id="findStudentById" parameterType="com.ssm.po.Student" resultMap="CardId">
        select * from tb_student where id = #{id}
    </select>
    <resultMap id="CardId" type="Student">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="sex" column="sex"/>
        <!--        一对一,association使用select属性引入另一条SQL语句 -->
        <association property="studentIdCard" column="card_id" javaType="StudentIdCard"
                     select="com.ssm.mapper.StudentIdCardMapper.findStudentIdCardById"/>
    </resultMap>
</mapper>

在上述两个映射文件中使用了MyBatis中的嵌套查询方式进行学生及其关联的学生证信息查询,因为返回的学生对象中除了基本属性外,还有一个关联的studentIdCard属性,所以需要手动编写结果映射。从映射文件StudentMapper.xml中可以看出,嵌套查询的方法是先执行一个简单的SQL语句,然后在进行结果映射时将关联对象在<association>元素中使用select属性执行另一条SQL语句(StudentIdCardMapper.xml中的SQL)。

步骤05 在核心配置文件mybatis-config.xml中引入Mapper映射文件并定义别名,如下所示。

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--    引入数据库连接配置文件-->
<!--    <properties resource="db.properties"/>-->
<!--    使用扫描包的形式定义别名-->
    <typeAliases>
        <package name="com.ssm.po"/>
    </typeAliases>
    <environments default="mysql">
<!--        1.2 配置id为mysql 的数据库环境-->
        <environment id="mysql">
<!--            使用JDBC的事务管理-->
            <transactionManager type="JDBC" />
<!--            数据库连接池-->
            <dataSource type="POOLED">
<!--                数据库驱动-->
                <property name="driver" value="com.mysql.jdbc.Driver" />
<!--                连接数据库的url-->
                <property name="url" value="jdbc:mysql://localhost:3306/db_mybatis" />
<!--                连接数据库的用户名-->
                <property name="username" value="root" />
<!--                连接数据库的用户名-->
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>
<!--2.配置 Mapper的位置-->
    <mappers>
        <mapper resource="com/ssm/mapper/UserMapper.xml" />
        <mapper resource="com/ssm/mapper/StudentMapper.xml" />
        <mapper resource="com/ssm/mapper/StudentIdCardMapper.xml" />
    </mappers>
</configuration>


在上述核心配置文件中,首先引入了数据库连接的配置文件,然后使用扫描包的形式自定义别名,接下来进行环境的配置,最后配置了Mapper映射文件的位置信息。

步骤06 在com.ssm.test包中创建测试类MybatisAssociatedTest,并在类中编写测试方法findStudentByIdTest(),如文件所示。

//MybatisAssociatedTest.java

package com.ssm.test;

import com.ssm.po.Student;
import com.ssm.po.User;
import com.ssm.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;

public class MybatisAssociatedTest {
    /*
     *嵌套查询
     */
    @Test
    public void findStudentByIdTest() {
        //通过工具类生成SqlSession对象
        SqlSession sqlSession = MybatisUtil.getSession();
        //执行SqlSession的查询办法,返回结果集
        Student student =
                sqlSession.selectOne("com.ssm.mapper.StudentMapper.findStudentById",1);
        System.out.println(student.toString());
        sqlSession.close();
    }
}

在findStudentByIdTest()方法中,首先通过MybatisUtils工具类获取了SqlSession对象,然后通过SqlSession对象的selectOne()方法获取了学生信息,最后关闭了SqlSession。执行方法后,控制台的输出结果如图所示。使用MyBatis嵌套查询的方式查询出了学生及其关联的学生证信息,这就是MyBatis中的一对一关联查询。

在这里插入图片描述

虽然使用嵌套查询的方式比较简单,但是嵌套查询的方式要执行多条SQL语句,这对于大型数据集合和列表展示不是很好,因为这样可能会导致成百上千条关联的SOL语句被执行,从而极大地消耗数据库性能,并且会降低查询效率。为此,MyBatis提供了嵌套结果的方式进行关联查询。

在StudentMapper.xml中,使用MyBatis嵌套结果的方式进行学生及其关联的学生证信息查询,所添加的代码如下所示。

<?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.ssm.mapper.StudentMapper">
    <!--    嵌套结果,通过嵌套结果映射来处理重复的联合结果的子集-->
    <select id="findStudentById2" parameterType="Integer" resultMap="CardId2">
        select s.* ,sidcard.code
        from tb_student s,tb_studentidcard sidcard
        where s.card_id = sidcard.id and s.id=#{id}
    </select>
    <resultMap id="CardId2" type="Student">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="sex" column="sex"/>
        <!--        一对一,association使用select属性引入另一条SQL语句 -->
        <association property="studentIdCard" javaType="StudentIdCard">
            <id property="id" column="card_id"/>
            <result property="code" column="code"/>
        </association>
    </resultMap>
</mapper>

从上述代码中可以看出,MyBatis嵌套结果的方式只编写了一条复杂的多表关联的SQL语句,并且在<association>元素中继续使用相关子元素进行数据库表字段和实体类属性的一一映射。执行结果相同,但使用MyBatis嵌套结果的方式只执行了一条SQL语句。

注意

在使用MyBatis嵌套查询方式进行关联查询映射时,使用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率。

MyBatis默认没有开启延迟加载,需要在核心配置文件mybatis-config.xml中的<settings>元素内进行配置,具体配置方式如下。

在这里插入图片描述
在映射文件中,MyBatis关联映射的<association>元素和<collection>元素中都已默认配置了延迟加载属性,即默认属性fetchType=“lazy”(属性fetchType="eager"表示立即加载),所以在配置文件中开启延迟加载后,无须在映射文件中再做配置。

2.2 一对多

在实际应用中,应用更多的关联关系是一对多(或多对一)。例如,一个班级有多个学生,即多个学生属于一个班级。使用MyBatis是怎么处理这种一对多关联关系的呢?之前所学的<resultMap>元素中包含一个<collection>子元素,MyBatis就是通过该元素来处理一对多关联关系的。<collection>子元素的属性大部分与<collection>元素相同,但其还包含一个特殊属性—ofType。ofType属性与javaType属性对应,用于指定实体对象中集合类属性所包含的元素类型。

<collection>元素可以参考如下两种示例进行配置,具体代码如下。

在这里插入图片描述

示例】在了解了MyBatis处理一对多关联关系的元素和方式后,接下来以班级和学生之间的这种一对多关联关系为例学习如何在MyBatis中处理一对多关联关系,具体步骤如下。

步骤01 在db_mybatis数据库中创建两个数据表:tb_banji和tb_student,同时在表中预先插入几条数据,执行的SQL语句如下所示。

#创建一个名称为tb_banji的表(暂添加少量字段)
CREATE TABLE tb_banji(
	id INT PRIMARY KEY AUTO_INCREMENT,
	name VARCHAR(32)
);
#插入两条数据
INSERT INTO tb_banji VALUES(1, '16软件技术1班');
INSERT INTO tb_banji VALUES(2, '16软件技术2班');
#创建一个名称为tb_student的表(暂时添加少量字段)
CREATE TABLE tb_student(
	id INT PRIMARY KEY AUTO_INCREMENT,
	name VARCHAR(32),
	sex CHAR(1),
	banji_id INT,
	FOREIGN KEY (banji_id) REFERENCES tb_banji (id)
);
#插入3条数据
INSERT INTO tb_student VALUES(1,'孙蕙','m',1);
INSERT INTO tb_student VALUES(2,'刘梦奕','f',1);
INSERT INTO tb_student VALUES(3,'无为','m',2);

步骤02 在com.ssm.po包中创建持久化类:班级类Banji和学生类StudentOne,并在两个类中定义相关属性和方法,如文件9.7和文件9.8所示。

//Banji.java 

package com.ssm.po;
import java.util.List;

/**
 * 功能描述
 *
 * @author: 衍生星球
 * @date: 2023年06月09日 16:07
 */

public class Banji {
    private Integer id;
    private String name;
    private List<Student> studentList;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id){
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Student> getStudentList() {
        return studentList;
    }

    public void setStudentList(List<Student> studentList) {
        this.studentList = studentList;
    }

    public String toString() {
        return "Banji [id=" + id + ",name=" + name + ",studentList=" + studentList + "]";
    }

}
//StudentOne.java

package com.ssm.po;

/**
 * 功能描述
 *
 * @author: 衍生星球
 * @date: 2023年06月09日 16:14
 */

public class StudentOne {
    private Integer id;
    private String name;
    private String sex;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "StudentOne [id=" + id + ", name=" + name + ", sex=" + sex + "]";
    }
}

步骤03 在com.ssm.mapper包中创建班级实体映射文件BanjiMapper.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.ssm.mapper.BanjiMapper">
    <!--一对多,查看某一班级及其关联的学生信息
    注意:若关联查出的列名相同,则需要使用别名区分-->
    <select id="findBanjiWithStudent" parameterType="Integer" resultMap="BanjiWithStudentResult">
        select b.* ,s.id as student_id,s.name
        from tb_banji b,tb_student s
        where b.id = s.banji_id and b.id=#{id}
    </select>
    <resultMap id="BanjiWithStudentResult" type="Banji">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!--一对多关系映射:collection
        ofType表示属性集合中的元素的类型List<Student>属性,即Student-->
        <collection property="studentList" ofType="Student">
            <id property="id" column="student_id"/>
            <result property="name" column="name"/>
            <result property="sex" column="sex"/>
        </collection>
    </resultMap>
</mapper>

在文件中使用MyBatis嵌套结果的方式定义了一个根据班级id查询班级及其关联的学生信息的select语句。因为返回的班级对象中包含Student集合对象属性,所以需要手动编写结果映射信息。

步骤04 将映射文件BanjiMapper.xml的路径配置到核心配置文件mybatis-config.xml中,其代码如下所示。

<mapper resource="com/ssm/mapper/BanjiMapper.xml" />

步骤05 在测试类MyBatisAssociatedTest中编写测试方法findBanjiTest()。

	@Test
    public void findStudentByIdTest() {
        //通过工具类生成SqlSession对象
        SqlSession sqlSession = MybatisUtil.getSession();
        //执行SqlSession的查询办法,返回结果集
        Banji banji =
                sqlSession.selectOne("com.ssm.mapper.BanjiMapper.findBanjiWithStudent",1);
        System.out.println(banji.toString());
        sqlSession.close();
    }

执行方法后,控制台输出结果如图所示。使用MyBatis嵌套结果的方式查询出了班级及其关联的学生集合信息。这就是MyBatis一对多的关联查询。

在这里插入图片描述
注意

上述案例从班级的角度出发,班级与学生之间是一对多的关联关系,但如果从单个学生的角度出发,一个学生只能属于一个班级,即一对一的关联关系。

2.3 多对多

在实际项目开发中,多对多的关联关系是非常常见的。以学生和课程为例,一个学生可以选修多门课程,而一门课程又可以被多个学生选修,学生和课程就属于多对多的关联关系。

在数据库中,多对多的关联关系通常使用一个中间表来维护,中间表选课表(electiveCourse)中的学生id(student_id)作为外键参照学生表的id,课程id(course_id)作为外键参照课程表的id。三个表的关联关系如图所示。

在这里插入图片描述

【示例】了解了数据库中学生表与课程表之间的多对多关联关系后,下面我们通过具体的案例来讲解如何使用MyBatis处理这种多对多的关系,具体实现步骤如下。

步骤01 创建数据表。在mybatis数据库中新建名称为tb_course和tb_electiveCourse的两个数据表(tb_student表已在前面的案例中创建,这里直接引用),同时在表中预先插入几条数据。其执行的SQL语句如下所示。

#创建一个名称为tb_course的表
CREATE TABLE tb_course (
	id INT PRIMARY KEY AUTO_INCREMENT,
	name VARCHAR(32),
	code VARCHAR(32)
);
#插入两条数据
INSERT INTO tb_course VALUES (1, 'Java程序设计语言','08113226');
INSERT INTO tb_course VALUES (2, 'Javaweb程序开发入门','08113228');

#创建一个名称为tb_electiveCourse的中间表
CREATE TABLE tb_electiveCourse (
	id INT PRIMARY KEY AUTO_INCREMENT,
	student_id INT,
	course_id INT,
	FOREIGN KEY (student_id) REFERENCES tb_student(id),
	FOREIGN KEY (course_id) REFERENCES tb_course(id)
);
#插入3条数据
INSERT INTO tb_electiveCourse VALUES (1,1,1);
INSERT INTO tb_electiveCourse VALUES (2,1,2);
INSERT INTO tb_electiveCourse VALUES (3,2,2);

步骤02 在com.ssm.po包中创建持久化类课程类Course,并在类中定义相关属性和方法,如文件所示。

//Course.java

package com.ssm.po;

import java.util.List;

/**
 * 功能描述
 *
 * @author: 衍生星球
 * @date: 2023年06月11日 23:01
 */

public class Course {
    private Integer id;
    private String name;
    private String code;
    private List<Student> studentlist;//于学生集合的关联属性

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public List<Student> getStudentlist() {
        return studentlist;
    }

    public void setStudentlist(List<Student> studentlist) {
        this.studentlist = studentlist;
    }

    @Override
    public String toString() {
        return "Course[id=" + id + ", name=" + name + ", code=" + code + "}";
    }
}

除了需要在课程持久化类中添加学生集合的属性外,还需要在学生持久化类(Student.java)中增加课程集合的属性及其对应的getter()/setter()方法,同时为了方便查看输出结果,需要重写toString()。Student类中添加的代码如下所示。

在这里插入图片描述

步骤03 在com.ssm.mapper包中创建课程实体映射文件CourseMapper.xml和学生实体映射文件StudentMapper.xml,对两个映射文件进行编辑后,如下文件所示。

//CourseMapper.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.ssm.mapper.CourseMapper">
    <!--    多对多嵌套查询:通过执行一条SQL映射语句来返回预期的特殊类型-->
    <select id="findCourseWithStudent" parameterType="Integer" resultMap="CourseWithStudentResult">
        select * from tb_course where id = #{id}
    </select>
    <resultMap id="CourseWithStudentResult" type="Course">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="code" column="code"/>
        <collection property="studentlist" column="id" ofType="Student"
    select="com.ssm.mapper.StudentMapper.findStudentById">
        </collection>
    </resultMap>
</mapper>

使用嵌套查询的方式定义了一个id为findCourseWithStudent的select语句来查询课程及其关联的学生信息。在<resultMap>元素中使用了<collection>元素来映射多对多的关联关系,其中property属性表示订单持久化类中的课程属性,ofType属性表示集合中的数据为Student类型,而column的属性值会作为参数执行StudentMapper.xml中定义的id为findStudentById的执行语句来查询订单中的学生信息。

//StudentMapper.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.ssm.mapper.StudentMapper">
    <!--    嵌套结果,通过嵌套结果映射来处理重复的联合结果的子集-->
    <select id="findStudentById" parameterType="Integer" resultType="Student">
        select * from tb_student where id in (
        select student_id from tb_electivecourse where course_id=#{id}
        )
    </select>
</mapper>

其中定义了一个id为findStudentById的执行语句,该执行语句中的SQL会根据课程id查询与该课程所关联的学生信息。由于课程和学生是多对多的关联关系,因此需要通过中间表来查询学生信息。

步骤04 将新创建的映射文件CourseMapper.xml和StudentMapper.xml的文件路径配置到核心配置文件mybatis-config.xml中,代码如下所示。

<mapper resource="com/ssm/mapper/CourseMapper.xml" />
<mapper resource="com/ssm/mapper/StudentMapper.xml" />

步骤05 在测试类MyBatisAssociatedTest中编写多对多关联查询的测试方法findCourseByIdTest(),其代码如下所示。

  /*
     *多对多嵌套查询
     */
    @Test
    public void findCourseByIdTest() {
        SqlSession sqlSession = MybatisUtil.getSession();
        //查询id为1的课程中的学生信息
        Course course =
                sqlSession.selectOne("com.ssm.mapper.CourseMapper.findCourseWithStudent",1);
        System.out.println(course);
        sqlSession.close();
    }

使用MyBatis嵌套查询的方式查询出了课程及其关联的学生信息,这就是MyBatis多对多的关联查询。

如果多表关联查询的SQL语句比较熟,就可以在CourseMapper.xml中使用嵌套结果的方式,其代码如下所示。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/640179.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全志V3S嵌入式驱动开发(wifi驱动)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 荔枝派上面除了支持v3s自带的有线网口&#xff0c;还带有一个支持sd协议的esp 8089 wifi模块。有了这个模块&#xff0c;v3s没有网线&#xff0c;也…

chatgpt赋能python:Python程序与SEO:如何建立程序使您的网站优化更好

Python程序与SEO&#xff1a;如何建立程序使您的网站优化更好 今天&#xff0c;越来越多的网站和在线业务转向搜索引擎优化&#xff0c;以吸引更多访问者和客户。Python编程语言是一种快速、灵活、易于学习的工具&#xff0c;如果正确使用它可以使您的网站SEO更好。下面我们来…

【从删库到跑路】MySQL系列——数据库的介绍MySQL的启动

&#x1f38a;专栏【MySQL】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【如愿】 大一同学小吉&#xff0c;欢迎并且感谢大家指出我的问题&#x1f970; 文章目录 &#x1f354;什么是数据库⭐组成⭐数据库的优势 &#x1f35…

Spring Security--自动登录

也就是remember me 在配置链上加一个 然后发送请求时加上:remember-me字段 value值可以为&#xff0c;ture&#xff0c;1&#xff0c;on 我们记住登录后&#xff0c;关掉浏览器再打开&#xff0c;访问一下接口&#xff0c;可以访问&#xff0c;说明记住登录成功了。 因为有的…

Spring中Bean的生命 周期与作用域

文章目录 前言Bean的作用域概念Bean作用域类型1. singleton&#xff1a;单例作⽤域2. prototype&#xff1a;原型作⽤域&#xff08;多例作⽤域&#xff09;3. request&#xff1a;请求作⽤域4. session&#xff1a;回话作⽤域5. application&#xff1a;全局作⽤域6. websocke…

51单片机实训项目之“红外控制小风扇”代码详解

本代码实现的功能是通过红外遥控来控制风扇的转速。废话不多说&#xff0c;直接上代码。 另外补充一点红外通信的原理&#xff1a; 红外接收 NEC协议&#xff1a; 数据格式 发射端的方波图&#xff0c;接收端的正好与之相反&#xff0c;数据传输从最低位开始 NEC 标准下…

mqtt.fx连接阿里云物联网平台

这里写目录标题 注册公共示例创建产品添加设备创建云产品流转生成基本信息配置mqtt.fx客户端数据传送 前提条件&#xff1a;下载mqtt.fx软件&#xff0c;以及注册好阿里云物联网平台账号 本实验用两个mqtt.fx客户端接入阿里云物联网平台&#xff0c;来实现不同设备间消息的传输…

大数据Doris(四十):Routine Load基本原理和语法介绍

文章目录 Routine Load基本原理和语法介绍 一、基本原理 二、Routine Load 语法 Routine Load基本原理和语法介绍 例行导入(Routine Load)功能,支持用户提交一个常驻的导入任务,通过不断的从指定的数据源读取数据,将数据导入到 Doris 中。目前Rou

chatgpt赋能python:如何使用Python获取Listview

如何使用Python获取Listview 在现代数据驱动的世界中&#xff0c;处理大量数据已经成为一项关键技能。准确地说&#xff0c;操作大量数据要比操作一小部分数据要困难得多。Python是一门非常出色的编程语言&#xff0c;它的处理大量数据的能力无人能敌。在这篇文章中&#xff0…

MySQL面试题详解

优化 如何定位慢查询 mysql中慢查询通常发生在以下几种情况&#xff0c;聚合查询&#xff0c;多表查询&#xff0c;表数据量过大查询&#xff0c;深度分页查询。 表象&#xff1a;页面加载过慢&#xff0c;接口压测响应时间过长(超过1s) 定位慢查询的方法主要有两种。方法一…

Windows 下编译 OpenCV 和 OpenCV-contrib

文章目录 导言环境准备源码获取环境获取 配置 CMake 并编译ConfigureGenerate 生成项目总结 导言 在本文中&#xff0c;我们将介绍如何在 Windows 系统下编译 OpenCV 和 OpenCV-contrib。OpenCV 是一个开源的计算机视觉库&#xff0c;它包含了许多图像处理和计算机视觉的功能。…

gismo调试-组总刚

文章目录 前言一、1 组总刚main文件的断点2 跳转到gsElasticityAssembler.hpp3 gsElasticityAssembler.hpp的177行进入gsVisitorLinearElasticity.h4 进入gsAssembler.h重新进入gsVisitorLinearElasticity.h进入gsSparseSystem.h1.14 进入gsAssembler.h1.21.31.4 二、2.12.22.3…

Cracking C++(11): CMake代码高亮调研

文章目录 1. 目的2. VSCode 插件CMake 和 CMake ToolsCMake Language SupportCMake Highlights 3. JetBrains 系列3.1 CLion3.2 Fleet 4. Kate5. Sublime Text6. 总结 1. 目的 CMake 已经是开源 C 项目的主流 building system&#xff0c; 这里简单调研关注的编辑器 / IDE 下&…

Jetson nano 进阶教程4_通过IIC输出PWM

Jetson nano 进阶教程4_通过IIC输出PWM Jetson nano的40PIN不能直接发出PWM波&#xff0c;在很多控制舵机&#xff0c;电机调速方面很不方便&#xff0c;因此利用一块PCA9685模块&#xff0c;通过I2C总线控制PCA9685输出pwm波&#xff0c;并且可以调整占空比。 How do I use P…

Android Activity启动过程详解

目录 一&#xff0c;背景介绍 二&#xff0c;Activity启动过程 2.1 调用 ATMS 系统进程 2.1.1 时序图 2.1.2 Launcher 桌面的 App 图标入口 2.1.3 startActivitySafely() 方法 2.1.4 execStartActivity() 方法 2.2 ATMS 向 AMS 发送创建应用进程的过程 2.2.1 时序图 …

03- 流程控制(C语言)

一 概述 C语言支持三种程序运行结构&#xff1a;顺序结构、选择结构、循环结构。 顺序结构&#xff1a;按照语句编写的顺序 上到下逐句执行。选择结构&#xff1a;也叫 分支结构&#xff0c;依据是否满足条件&#xff0c;有选择的执行相应功能。循环结构&#xff1a;依据条件…

动态字符串SDS

基本概括 Redis中保存的Key是字符串&#xff0c;value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。 但Redis没有直接使用C语言中的字符串&#xff0c;因为C语言字符串存在很多问题&#xff08;C语言中实际上没有字符串&#xff0c;本质上是字符数…

面向对象的封装

9. 面向对象特征一&#xff1a;封装性(encapsulation) 什么是封装 就像快递一样我们在网上买的物品&#xff0c;快递都会给我们添加外包装&#xff0c;给我们封装起来&#xff0c;这就是封装 客观世界里每一个事物的内部信息都隐藏在其内部&#xff0c;外界无法直接操作和修改…

怎样才算一个计算机知识体系完整的毕业生

为什么突然想写这个话题呢&#xff1f; 最近有不少新关注的读者&#xff0c;在后台问&#xff1a;大学学 Java 和 C 哪个好找工作&#xff0c;学前端好还是后端好&#xff0c;该学 Vue 还是 React。。。 仿佛看到了自己当年的模样&#xff0c;所以觉得有必要单独写一篇文章&a…

CSS基础学习--8 盒子模型(Box Model)

一、介绍 所有HTML元素可以看作盒子&#xff0c;在CSS中&#xff0c;"box model"这一术语是用来设计和布局时使用。 CSS盒模型本质上是一个盒子&#xff0c;封装周围的HTML元素&#xff0c;它包括&#xff1a;边距&#xff0c;边框&#xff0c;填充&#xff0c;和实…