03.关系映射

一、实体关系

实体——数据实体,实体关系指的就是数据与数据之间的关系

例如:用户和角色、房屋和楼栋、订单和商品

实体关系分为以下四种:

一对一关联

实例:学生和校园卡、人和身份证、用户基本信息和详情

数据表关系:

  • 主键关联(学生表主键和校园卡表主键相同时,表示是匹配的数据)

学生和校园卡

  • 唯一外键关联

学生和校园卡

  

一对多关联多对一关联

实例:

  • 一对多: 班级和学生、 类别和商品、楼栋和房屋

  • 多对一:学生和班级 、 商品和类别

数据表关系:

  • 在“多”的一方添加外键和“一”的一方进行关联。 

学生和班级

 

多对多关联

实例:任课老师和班级、任课老师和学生、学生和社团、用户和角色、角色和权限、订单和商品。

数据表关系:建立第三张关系表添加两个外键分别与两张表主键进行关联。

学生和课程及成绩

 任课教师和班级

二、创建项目部署MyBatis框架

(一)创建Web项目

项目名称:MyBatisTest2

添加Web4.0支持。

   

在pom.xml文件中添加Maven依赖(Servlet支持):

<!-- 添加web依赖 -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

 

如果测试jsp页面出现404错误,无法访问jsp,可以在【项目结构】->【工件】->【输出布局】中,添加项目的web目录。

 

(二)部署MyBatis框架

 在pom.xml文件中添加Maven依赖(MyBatis支持和MySQL数据库驱动): 

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.13</version>
</dependency>

我们使用Maven方式添加jar包,在发布项目之前一定要在【项目结构】--【工件】中将Maven方式导入的包(右侧)添加到【输出根】(左侧)中。

(三)创建数据库连接配置文件

src/main/resources目录下创建db.properties文件,在该文件中配置数据库连接的参数。

mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/db_test?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
mysql.username=root
mysql.password=1234

(四)创建MyBatis核心配置文件

src/main/resources目录下创建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"/>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!-- 数据库连接配置,db.properties文件中的内容 -->
            <dataSource type="POOLED">
                <property name="driver" value="${mysql.driver}"/>
                <property name="url" value="${mysql.url}"/>
                <property name="username" value="${mysql.username}"/>
                <property name="password" value="${mysql.password}"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

三、一对一关联

案例:学生(1) -- 校园卡(1)

(一)创建数据表

CREATE TABLE tb_student (
    sid INT PRIMARY KEY auto_increment,
    sname VARCHAR(20) NOT NULL,
    age INT 
);
CREATE TABLE tb_card ( cid INT PRIMARY KEY auto_increment, balance DOUBLE NOT NULL, sid INT NOT NULL UNIQUE
-- CONSTRAINT FK_STUDENT FOREIGN KEY(sid) REFERENCES tb_student(sid) -- 物理外键关联,不推荐使用 );

现在很多大公司都“不推荐使用物理外键关联”,其中原因,大家可以自行上网搜索学习。https://blog.csdn.net/corleone_4ever/article/details/106540079

添加数据,可以使用Navicat【数据生成】功能,添加一些测试数据。

 

 

 

 

(二)创建实体类

我们在这里给大家介绍一下Lombok。Lombok项目是一个Java库,它可以自动插入到编辑器和构建工具中,增强Java的性能。不需要再写构造方法、getter和setter等方法,通过使用对应的注解,可以在编译源码的时候动态添加源码。

Lombok是一个可以大幅减少Java代码的工具。

导入Lombok依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.26</version>
    <scope>provided</scope>
</dependency>
  • @Getter/@Setter

  为字段生成Getter和Setter方法,可以注解到字段或者类上(注解在类上会为类中的所有字段生成Getter和Setter方法),默认是public类型的,如果需要的话可以修改方法的访问级别。

  • @NonNull

  为字段赋值时(即调用字段的setter方法时),如果传的参数为null,则会抛出空异常NullPointerException,生成setter方法时会对参数是否为空检查。

  • @NoArgsConstructor

  生成一个无参构造方法。当类中有final字段没有被初始化时,编译器会报错,此时可用@NoArgsConstructor(force = true),然后就会为没有初始化的final字段设置默认值 0 / false / null, 这样编译器就不会报错。对于具有约束的字段(例如@NonNull字段),不会生成检查或分配,因此请注意,正确初始化这些字段之前,这些约束无效。

  • @RequiredArgsConstructor

  生成构造方法(可能带参数也可能不带参数),如果带参数,这参数只能是以final修饰的未经初始化的字段,或者是以@NonNull注解的未经初始化的字段。

  @RequiredArgsConstructor(staticName = “of”)会生成一个of()的静态方法,并把构造方法设置为私有的。

  • @AllArgsConstructor

  生成一个全参数的构造方法。

  • @ToString

  生成toString()方法,默认情况下它会按顺序(以逗号分隔)打印你的类名称以及每个字段。可以这样设置不包含哪些字段,可以指定一个也可以指定多个@ToString(exclude = “id”) / @ToString(exclude = {“id”,“name”})

  如果继承的有父类的话,可以设置callSuper 让其调用父类的toString()方法,例如:@ToString(callSuper = true)

  • @Data

  @Data 包含了 @ToString、@EqualsAndHashCode、@Getter / @Setter和@RequiredArgsConstructor的功能。

Student类

package com.sdbi.pojo;

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

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Student {
    private int sid;
    private String sname;
    private int age;
}

Card类

package com.sdbi.pojo;

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

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Card {
    private int cid;
    private double balance;
    private int sid;
}

将上一张中创建的com.sdbi.util.MyBatisUtil类复制到本项目中。

MyBatisUtil工具类
package com.sdbi.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.Reader;

public class MyBatisUtil {
    private static final SqlSessionFactory factory;
    private static ThreadLocal<SqlSession> local = new ThreadLocal<SqlSession>();

    static {
        String resource = "mybatis-config.xml";
        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader(resource);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        factory = new SqlSessionFactoryBuilder().build(reader);
    }

    public static SqlSessionFactory getFactory() {
        return factory;
    }

    private static SqlSession getSession(boolean isAutoCommit) {
        SqlSession session = local.get();
        if (session == null) {
            session = factory.openSession(isAutoCommit); // true,自动提交;false,手动提交
            local.set(session);
        }
        return session;
    }

    public static SqlSession getSession() { // 获取手动提交事务的session
        return getSession(false);
    }

    // T泛型,参数化的数据类型,
    public static <T extends Object> T getMapper(Class<T> c) {
        return getSession(true).getMapper(c);
    }
}

(三)添加操作(事务)

以学生注册为例,学生在注册时,一般有两种操作方式:

(1)学生注册时,先在学生表中添加学生数据,等后期再办校园卡时,在校园卡表中增加金额数据。(这种比较常见)

(2)学生注册时,同步办理校园卡,这时需要同时在两个表中都增加数据。(我们这里以这种方式为例)

因为要在两个表中同时添加数据,所以我们要使用事务

  • 在com.sdbi.mapper包下,新建两个Dao层接口:StudentMapper.java和CardMapper.java。
  • 在resources资源文件夹下,新建一个mapper文件夹,在该文件夹下新建两个映射文件:StudentMapper.xml和CardMapper.xml。
StudentMapper.java
package com.sdbi.mapper;

import com.sdbi.pojo.Student;

public interface StudentMapper {
    int insertStudent(Student student);
}

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.sdbi.mapper.StudentMapper">
    <insert id="insertStudent" useGeneratedKeys="true" keyProperty="sid">
        INSERT INTO tb_student (sname, age)
        VALUES (#{sname}, #{age})
    </insert>
</mapper>
CardMapper.java
package com.sdbi.mapper;

import com.sdbi.pojo.Card;

public interface CardMapper {
    int insertCard(Card card);
}

CardMapper.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.sdbi.mapper.CardMapper">
    <insert id="insertCard" useGeneratedKeys="true" keyProperty="cid">
        INSERT INTO tb_card (balance, sid)
        VALUES (#{balance}, #{sid})
    </insert>
</mapper>
在核心配置文件mybatis-config.xml中添加XxxMapper.xml文件的引入。
<mappers>
    <mapper resource="/mapper/StudentMapper.xml"/>
    <mapper resource="/mapper/CardMapper.xml"/>
</mappers>

TestServlet.java

package com.sdbi.servlet;

import com.sdbi.mapper.CardMapper;
import com.sdbi.mapper.StudentMapper;
import com.sdbi.pojo.Card;
import com.sdbi.pojo.Student;
import com.sdbi.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("TestServlet.doGet()...start");
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().println("实体关系实例");
        insertStudent();
        System.out.println("TestServlet.doGet()...end");
    }

    private void insertStudent() {
        SqlSession session = MyBatisUtil.getSession();
        try {
            Student student = new Student(0, "张三", 20);
            StudentMapper studentMapper = session.getMapper(StudentMapper.class);
            studentMapper.insertStudent(student);
            System.out.println(student.toString());
            Card card = new Card(0, 222, student.getSid());
            CardMapper cardMapper = session.getMapper(CardMapper.class);
            cardMapper.insertCard(card);
            System.out.println(card.toString());
            session.commit(); // 事务提交
        } catch (Exception e) {
            e.printStackTrace();
            session.rollback(); // 事务回滚
        }
    }
}

运行程序,查看数据库中的tb_student和tb_card表,各增加了一条数据。 

(四)一对一关联查询

在Student实体类中,增加一个Card类型的属性card,表示该学生的校园卡信息。

Student.java

package com.sdbi.pojo;

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

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Student {
    private int sid;
    private String sname;
    private int age;

    private Card card;
}

1、连接查询方式

在StudentMapper.java接口中增加一个方法。
List<Student> selectStudent(String name);

在StudentMapper.xml映射文件中增加:

<resultMap id="studentMap" type="com.sdbi.pojo.Student">
    <id column="sid" property="sid"/>
    <result column="sname" property="sname"/>
    <result column="age" property="age"/>
    <result column="cid" property="card.cid"/>
    <result column="balance" property="card.balance"/>
    <result column="sid" property="card.sid"/>
</resultMap>

<select id="selectStudent" resultMap="studentMap">
    SELECT s.sid, s.sname, s.age, c.cid, c.balance, c.sid
    FROM tb_student s
             INNER JOIN tb_card c ON s.sid = c.sid
    WHERE s.sname = #{sname}
</select>

业务层代码TestServlet

package com.sdbi.servlet;

import com.sdbi.mapper.StudentMapper;
import com.sdbi.pojo.Student;
import com.sdbi.util.MyBatisUtil;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("TestServlet.doGet()...start");
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().println("实体关系实例");
        selectStudent();
        System.out.println("TestServlet.doGet()...end");
    }
  private void selectStudent() {
        StudentMapper studentMapper = MyBatisUtil.getMapper(StudentMapper.class);
        List<Student> list = studentMapper.selectStudent("张三");
        for (Student student : list) {
            System.out.println(student.toString());
        }
    }
}

运行结果:

课堂练习

查询所有学生的信息,包括每个人的余额。

2、子查询方式

在StudentMapper.java接口中增加一个方法。

List<Student> queryStudent(String name);

在StudentMapper.xml映射文件中增加:

<resultMap id="cardMap" type="com.sdbi.pojo.Card">
    <id column="cid" property="cid"/>
    <result column="balance" property="balance"/>
    <result column="sid" property="sid"/>
</resultMap>

<select id="queryCardById" resultMap="cardMap">
    SELECT cid, balance, sid
    FROM tb_card
    WHERE sid = #{sid}
</select>

<resultMap id="stuMap" type="com.sdbi.pojo.Student">
    <id column="sid" property="sid"/>
    <result column="sname" property="sname"/>
    <result column="age" property="age"/>
    <!--通过association关联子查询,查询一个对象-->
    <association property="card" select="com.sdbi.mapper.StudentMapper.queryCardById" column="sid"/>
</resultMap>

<select id="queryStudent" resultMap="stuMap">
    SELECT sid, sname, age
    FROM tb_student
    WHERE sname = #{sname}
</select>

业务层代码TestServlet

package com.sdbi.servlet;

import com.sdbi.mapper.StudentMapper;
import com.sdbi.pojo.Student;
import com.sdbi.util.MyBatisUtil;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("TestServlet.doGet()...start");
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().println("实体关系实例");
        selectStudent();
        System.out.println("TestServlet.doGet()...end");
    }
    private void selectStudent() {
        StudentMapper studentMapper = MyBatisUtil.getMapper(StudentMapper.class);
        List<Student> list = studentMapper.queryStudent("张三");
        for (Student student : list) {
            System.out.println(student.toString());
        }
    }
}

运行结果:

四、一对多关联

案例:班级(1)-- 学生(n)

当查询一个班级的时候, 要关联查询出这个班级下的所有学生。

(一)创建数据表

CREATE TABLE tb_student (
    sid INT PRIMARY KEY auto_increment,
    sname VARCHAR(20) NOT NULL,
    age INT,
    cid INT NOT NULL
);

CREATE TABLE tb_class (
    cid INT PRIMARY KEY auto_increment,
    cname VARCHAR(20) NOT NULL,
    sum INT NOT NULL
);

(二)创建实体类

Clazz类

package com.sdbi.pojo;

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

import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Clazz {
    private int cid;
    private String cname;
    private int sum;

    private List<Student> students; // 存储当前班级下的学生列表
}

Student类

package com.sdbi.pojo;

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

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Student {
    private int sid;
    private String sname;
    private int age;
    private int cid; // 班级id
}

(三)关联查询

1、连接查询方式

查询班级和班内学生时,不单独定义接口和映射文件了。

修改StudentMapper.java接口,增加抽象方法。

List<Clazz> selectClass(String className);

修改StudentMapper.xml文件,增加以下代码。

<resultMap id="classMap" type="com.sdbi.pojo.Clazz">
    <id column="cid" property="cid"/>
    <result column="cname" property="cname"/>
    <result column="sum" property="sum"/>

    <collection property="students" ofType="com.sdbi.pojo.Student">
        <id column="sid" property="sid"/>
        <result column="sname" property="sname"/>
        <result column="age" property="age"/>
        <result column="cid" property="cid"/>
    </collection>
</resultMap>

<select id="selectClass" resultMap="classMap">
    SELECT c.cid, c.cname, c.sum, s.sid, s.sname, s.age, s.cid
    FROM tb_class c
             INNER JOIN tb_student s ON c.cid = s.cid
    WHERE c.cname = #{cname}
</select>

业务层调用

private void selectClass() {
    StudentMapper studentMapper = MyBatisUtil.getMapper(StudentMapper.class);
    List<Clazz> list = studentMapper.selectClass("21软件2班");
    for (Clazz clazz : list) {
        System.out.println(clazz.toString());
    }
}

2、子查询方式

修改StudentMapper.java接口,增加抽象方法。

List<Clazz> queryClass(String className);

修改StudentMapper.xml文件,增加以下代码。

<select id="listStudentByCid" resultType="com.sdbi.pojo.Student">
    SELECT sid, sname, age, cid
    FROM tb_student
    WHERE cid = #{cid}
</select>

<resultMap id="clazzMap" type="com.sdbi.pojo.Clazz">
    <id column="cid" property="cid"/>
    <result column="cname" property="cname"/>
    <result column="sum" property="sum"/>

    <collection property="students" select="com.sdbi.mapper.StudentMapper.listStudentByCid" column="cid"/>
</resultMap>

<select id="queryClass" resultMap="clazzMap">
    SELECT cid, cname, sum
    FROM tb_class
    WHERE cname = #{cname}
</select>

业务层调用

private void selectClass() {
    StudentMapper studentMapper = MyBatisUtil.getMapper(StudentMapper.class);
    List<Clazz> list = studentMapper.queryClass("21软件2班");

    for (Clazz clazz : list) {
        System.out.println(clazz.toString());
    }
}

以上两种方式,在控制台都能输出一个班级包含了多名学生。

五、多对一关联

实例:学生(n) — 班级(1)

当查询一个学生的时候,关联查询这个学生所在的班级信息

(一)修改实体类

Student类

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Student {
    private int sid;
    private String sname;
    private int age;
//    private int cid; // 班级id
    
    private Clazz clazz; // 学生所在班级
}

Clazz类

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Clazz {
    private int cid;
    private String cname;
    private int sum;

//    private List<Student> students; // 存储当前班级下的学生列表
}

(二)关联查询

1、连接查询方式

修改StudentMapper.java接口,去掉之前的方法,增加抽象方法。

List<Student> selectStudentBySid(int sid);

修改StudentMapper.xml文件,去掉之前的代码,增加以下代码。

<resultMap id="studentClassMap" type="com.sdbi.pojo.Student">
    <id column="sid" property="sid"/>
    <result column="sname" property="sname"/>
    <result column="age" property="age"/>
    <result column="cid" property="clazz.cid"/>
    <result column="cname" property="clazz.cname"/>
    <result column="sum" property="clazz.sum"/>
</resultMap>

<select id="selectStudentBySid" resultMap="studentClassMap">
    SELECT s.sid, s.sname, s.age, c.cid, c.cname, c.sum
    FROM tb_student s
             INNER JOIN tb_class c ON s.cid = c.cid
    WHERE s.sid = #{sid}
</select>

业务层调用

private void selectStudent() {
    StudentMapper studentMapper = MyBatisUtil.getMapper(StudentMapper.class);
    List<Student> list = studentMapper.selectStudentBySid(30); // 查询学号为30的学生
    for (Student student : list) {
        System.out.println(student.toString());
    }
}

运行结果

2、子查询方式

修改StudentMapper.java接口,增加抽象方法。

List<Student> queryStudentBySid(int sid);

修改StudentMapper.xml文件,增加以下代码。

<select id="queryClassByCid" resultType="com.sdbi.pojo.Clazz">
    SELECT cid, cname, sum
    FROM tb_class
    WHERE cid = #{cid}
</select>

<resultMap id="stuClassMap" type="com.sdbi.pojo.Student">
    <id column="sid" property="sid"/>
    <result column="sname" property="sname"/>
    <result column="age" property="age"/>
    <association property="clazz" select="com.sdbi.mapper.StudentMapper.queryClassByCid" column="cid"/>
</resultMap>

<select id="queryStudentBySid" resultMap="stuClassMap">
    SELECT sid, sname, age, cid
    FROM tb_student
    WHERE sid = #{sid}
</select>

业务层调用

private void selectStudent() {
    StudentMapper studentMapper = MyBatisUtil.getMapper(StudentMapper.class);
    List<Student> list = studentMapper.queryStudentBySid(35); // 查询学号为35的学生
    for (Student student : list) {
        System.out.println(student.toString());
    }
}

以上两种方式,在控制台都能输出一名学生和他所对应的班级信息。

六、多对多关联

案例:学生(m)-- 课程(n)

(一)创建数据表

-- 学生信息表(如上)
CREATE TABLE tb_student (
    sid INT PRIMARY KEY auto_increment,
    sname VARCHAR(20) NOT NULL,
    age INT,
    cid INT NOT NULL
);
-- 课程信息表
CREATE TABLE tb_course (
    course_id INT PRIMARY KEY auto_increment,
    course_name VARCHAR(20) NOT NULL
);
-- 选课信息表/成绩表(学号、课程号、成绩)
CREATE TABLE tb_grade (
    sid INT NOT NULL,
    course_id INT NOT NULL,
    score INT NOT NULL
);

(二)案例1:查询学生时,同时查询学生所选的课程

1、创建实体类

Student类

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Student {
    private int sid;
    private String sname;
    private int age;

    private List<Course> courses; // 学生所选课程
}

Course类

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Course {
    private int courseId;
    private String courseName;
}

2、连接查询方式

修改StudentMapper.java接口,增加抽象方法。

List<Student> selectStudentBySname(String sname);

修改StudentMapper.xml文件,增加以下代码。

<resultMap id="studentCourseMap" type="com.sdbi.pojo.Student">
    <id column="sid" property="sid"/>
    <result column="sname" property="sname"/>
    <result column="age" property="age"/>
    <collection property="courses" ofType="com.sdbi.pojo.Course">
        <id column="course_id" property="courseId"/>
        <result column="course_name" property="courseName"/>
    </collection>
</resultMap>
<select id="selectStudentBySname" resultMap="studentCourseMap">
    SELECT s.sid, s.sname, s.age, c.course_id, c.course_name
    FROM tb_student s
             INNER JOIN tb_grade g
             INNER JOIN tb_course c
                        ON s.sid = g.sid AND g.course_id = c.course_id
    WHERE s.sname = #{sname}
</select>

业务层调用

private void selectStudent() {
    StudentMapper studentMapper = MyBatisUtil.getMapper(StudentMapper.class);
    List<Student> list = studentMapper.selectStudentBySname("张三");
    for (Student student : list) {
        System.out.println(student.toString());
    }
}

运行结果

3、子查询方式

修改StudentMapper.java接口,增加抽象方法。

List<Student> queryStudentBySname(String sname);

修改StudentMapper.xml文件,增加以下代码。

<resultMap id="courseMap" type="com.sdbi.pojo.Course">
    <id column="course_id" property="courseId"/>
    <result column="course_name" property="courseName"/>
</resultMap>

<select id="queryCourseBySid" resultMap="courseMap">
    SELECT c.course_id, c.course_name
    FROM tb_course c
             INNER JOIN tb_grade g
                        ON g.course_id = c.course_id
    WHERE g.sid = #{sid}
</select>

<resultMap id="stuMap" type="com.sdbi.pojo.Student">
    <id column="sid" property="sid"/>
    <result column="sname" property="sname"/>
    <result column="age" property="age"/>
    <collection property="courses" select="queryCourseBySid" column="sid"/>
</resultMap>

<select id="queryStudentBySname" resultMap="stuMap">
    SELECT sid, sname, age
    FROM tb_student
    WHERE sname = #{sname}
</select>

业务层调用

private void selectStudent() {
    StudentMapper studentMapper = MyBatisUtil.getMapper(StudentMapper.class);
    List<Student> list = studentMapper.queryStudentBySname("王五");
    for (Student student : list) {
        System.out.println(student.toString());
    }
}

运行结果

案例2:根据课程编号查询课程时,同时查询选择了这门课程的学生

1、创建实体类

Student类

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Student {
    private int sid;
    private String sname;
    private int age;
}

Course类

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Course {
    private int courseId;
    private String courseName;

    private List<Student> students;
}

2、连接查询方式

修改StudentMapper.java接口,增加抽象方法。

List<Course> selectCourseByName(String courseName);

修改StudentMapper.xml文件,增加以下代码。

<resultMap id="courseMap2" type="com.sdbi.pojo.Course">
    <id column="course_id" property="courseId"/>
    <result column="course_name" property="courseName"/>
    <collection property="students" ofType="com.sdbi.pojo.Student">
        <id column="sid" property="sid"/>
        <result column="sname" property="sname"/>
        <result column="age" property="age"/>
    </collection>
</resultMap>

<select id="selectCourseByName" resultMap="courseMap2">
    SELECT c.course_id, c.course_name, s.sid, s.sname, s.age
    FROM tb_course c
             INNER JOIN tb_grade g
             INNER JOIN tb_student s
                        ON c.course_id = g.course_id AND g.sid = s.sid
    WHERE c.course_name = #{name}
</select>

业务层调用

private void selectCourse() {
    StudentMapper studentMapper = MyBatisUtil.getMapper(StudentMapper.class);
    List<Course> list = studentMapper.selectCourseByName("Java");
    for (Course course : list) {
        System.out.println(course.toString());
    }
}

3、子查询方式

修改StudentMapper.java接口,增加抽象方法。

List<Course> queryCourseByName(String courseName);

修改StudentMapper.xml文件,增加以下代码。

<select id="queryStudentByCourseId" resultType="com.sdbi.pojo.Student">
    SELECT s.sid, s.sname, s.age
    FROM tb_student s
             INNER JOIN tb_grade g
                        ON g.sid = s.sid
    WHERE g.course_id = #{course_id}
</select>

<resultMap id="courseMap3" type="com.sdbi.pojo.Course">
    <id column="course_id" property="courseId"/>
    <result column="course_name" property="courseName"/>
    <collection property="students" select="queryStudentByCourseId" column="course_id"/>
</resultMap>

<select id="queryCourseByName" resultMap="courseMap3">
    SELECT course_id, course_name
    FROM tb_course
    WHERE course_name = #{name}
</select>

业务层调用

private void selectCourse() {
    StudentMapper studentMapper = MyBatisUtil.getMapper(StudentMapper.class);
    List<Course> list = studentMapper.queryCourseByName("Java");
    for (Course course : list) {
        System.out.println(course.toString());
    }
}

运行结果

 

posted @ 2023-04-25 15:00  熊猫Panda先生  阅读(735)  评论(0编辑  收藏  举报