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类复制到本项目中。
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。
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>
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>
<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、连接查询方式
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()); } }
以上两种方式,在控制台都能输出一个班级包含了多名学生。
五、多对一关联
@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()); } }
运行结果