• MyBatis之级联——一对多关系


    上次我们讲到了MyBatis的一对一关系的表示,简单回顾一下一对一关系就是一个学生只有一个学生证。那么什么是一对多关系呢?一个学生有多个课程这就是一对多的关系。我们结合上一章中的学生和学生证,在此基础上新增一个课程表和课程成绩表。学生对应课程表是一对多的关系,在学生确定的情况下课程表对应课程成绩是一对一的关系。我们先来看看我们所假设的场景数据结构的设计。

    数据库的ER图如下(因为对数据库还处于菜鸟阶段……所以可能ER图绘制有误,但不影响我们讲解MyBatis一对多关系的级联):

    再看看数据库的物理模型包含哪些字段:

    数据库的设计就差不多了,接下来是设计我们的POJO类:

    首先是Student类:

     1 package day_8_mybatis.pojo;
     2 
     3 import java.util.List;
     4 
     5 /**
     6  * @author turbo
     7  *
     8  * 2016年11月4日
     9  */
    10 public class Student {
    11     private int id;
    12     private String name;
    13     private String sex;
    14     private SelfCard selfCard;  //学生和学生证是一对一的关系,所以存放一个对学生证类的引用
    15     private List<CourseScore> courseScoreList;  //我们在一开始就提到过学生和课程是一对多的关系,所以学生POJO类中对课程类字段就是一个List用来存放学生的课程成绩。
    16     //省略set/get方法      
    17 }

    注意,我们有一个List字段是对课程成绩的引用而不是课程的引用。为什么呢?因为在我们数据库设计中,学生和课程是通过课程成绩联系起来的。

    接着是我们的CourseScore类:

     1 package day_8_mybatis.pojo;
     2 
     3 /**
     4  * @author turbo
     5  *
     6  * 2016年11月4日
     7  */
     8 public class CourseScore {
     9     private int id;
    10     private int studentId;
    11     private Course course;  //在学生id确认的情况下,课程和成绩是一对一的关系。
    12     private String score;
    13     //省略set/get方法  
    14 }

    最后是Course类:

     1 package day_8_mybatis.pojo;
     2 
     3 /**
     4  * @author turbo
     5  *
     6  * 2016年11月4日
     7  */
     8 public class Course {
     9     private int id;
    10     private String courseName;
    11     private String note;
    12     //省略set/get方法
    13 }

    现在我们是要通过一个学生ID,就能查询出这个学生的课程、以及对应课程的成绩。这个怎么来实现呢?在使用MyBatis为我们提供的级联前,我们先来梳理一下从逻辑上是怎么一步一步查询出来的。

    我们要通过学生id查询出学生的基本信息(包括课程以及对应的成绩),但在学生POJO类中有一个对课程成绩的List引用(暂时忽略学生证),也就是说我们无法一条简单的sql语句(无join的sql语句)查询出结果。但是!我们可以通过student_id在课程成绩表中查询出该学生的相应课程id(注意此时还是id),但我们此时还是没办法知道具体的课程名,再利用我们上一步中student_id查询出的course_id通过课程表再来查询出对应的课程名。重新梳理一下:

    1. 通过student_id在t_student表中查询学生基本信息(name,sex)
    2. 通过student_id在t_course_score表中查询学生对应的course_id
    3. 通过course_id在t_course表中查询课程

    那我们现在就从最底层做起,也就是通过course_id查询出具体课程,因为这不会涉及到其他表。

     1 package day_8_mybatis.mapper;
     2 
     3 import day_8_mybatis.pojo.Course;
     4 
     5 /**
     6  * @author turbo
     7  *
     8  * 2016年11月4日
     9  */
    10 public interface CourseMapper {
    11     Course getCourse(int id);  //此id为course_id
    12 }

    再来看看mapper映射,也是非常简单。

    1 <?xml version="1.0" encoding="UTF-8"?>
    2 <!DOCTYPE mapper  
    3   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
    4   "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 
    5 <mapper namespace="day_8_mybatis.mapper.CourseMapper">
    6     <select id="getCourse" parameterType="int" resultType="day_8_mybatis.pojo.Course">
    7         select id, course_name as courseName, note from t_course where id = #{id}
    8     </select>
    9 </mapper>

    现在已经写好了通过course_id来查询出具体课程。那么就是倒着走到第2步,通过student_id在t_course_score表中查询学生对应的course_id,在最开始说过,在学生确定的情况下,课程和课程成绩是一对一的关系,关于一对一的关系我们在上一篇已经讲过,不妨再重温一下。

     1 package day_8_mybatis.mapper;
     2 
     3 import day_8_mybatis.pojo.CourseScore;
     4 
     5 /**
     6  * @author turbo
     7  *
     8  * 2016年11月4日
     9  */
    10 public interface CourseScoreMapper {
    11     CourseScore findCourseScoreByStudentId(int id);
    12 }

    再来看看mapper映射,也是非常简单。

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE mapper  
     3   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
     4   "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 
     5 <mapper namespace="day_8_mybatis.mapper.CourseScoreMapper">
     6     <resultMap id="courseScoreMap" type="day_8_mybatis.pojo.CourseScore">
     7         <id property="id" column="id"/>
     8         <result property="studentId" column="student_id"/>
     9         <result property="score" column="score"/>
    10         <association property="course" column="course_id" select="day_8_mybatis.mapper.CourseMapper.getCourse" />  <!--将查询出来的course_id交给CouseMapper来查询出具体课程信息-->
    11     </resultMap>
    12     
    13     <select id="findCourseScoreByStudentId" parameterType="int" resultMap="courseScoreMap">
    14         select id, student_id, course_id, score from t_course_score where student_id = #{id}
    15     </select>
    16 </mapper>

    最后一步,也就是第1步,才进入正题MyBatis的一对多collection级联关系。

     1 package day_8_mybatis.mapper;
     2 
     3 import day_8_mybatis.pojo.Student;
     4 
     5 /**
     6  * @author turbo
     7  *
     8  * 2016年11月4日
     9  */
    10 public interface StudentMapper {
    11     Student getStudent(int id);
    12 }

    关键在mapper映射中。

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE mapper  
     3   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
     4   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
     5 <mapper namespace="day_8_mybatis.mapper.StudentMapper">
     6     <resultMap type="day_8_mybatis.pojo.Student" id="studentMap">
     7         <id property="id" column="id"/>
     8         <result property="name" column="name"/>
     9         <result property="sex" column="sex"/>
    10         <association property="selfCard" column="id" select="day_8_mybatis.mapper.SelfCardMapper.findSelfCardByStudentId"/>
    11         <collection property="courseScoreList" column="id" select="day_8_mybatis.mapper.CourseScoreMapper.findCourseScoreByStudentId" />
    12         </resultMap>
    13     <select id="getStudent" parameterType="int" resultMap="studentMap">
    14         select id, name, sex from t_student where id = #{id}
    15     </select>
    16 </mapper>

    请好好仔细品味品味,仔细回顾整个查询的逻辑过程。collection就是MyBatis为我们提供的第二个级联关系——一对多。

    最后上我们的测试代码:

     1 package day_8_mybatis;
     2 
     3 import java.io.IOException;
     4 import java.io.InputStream;
     5 
     6 import org.apache.ibatis.io.Resources;
     7 import org.apache.ibatis.session.SqlSession;
     8 
     9 import day_8_mybatis.mapper.StudentMapper;
    10 import day_8_mybatis.pojo.Student;
    11 import day_8_mybatis.util.SessionFactory2;
    12 
    13 /**
    14  * 客户端
    15  * @author turbo
    16  *
    17  * 2016年11月4日
    18  */
    19 public class Main {
    20 
    21     /**
    22      * @param args
    23      * @throws IOException 
    24      */
    25     public static void main(String[] args) throws Exception {
    26         String resource = "day_8_mybatis/mybatis-config.xml";        //获取mybatis配置文件路径
    27         InputStream inputStream = Resources.getResourceAsStream(resource);
    28         SqlSession sqlSession = SessionFactory2.getInstance(inputStream).openSession();
    29         StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
    30         Student student = studentMapper.getStudent(1);
    31         System.out.println("学生:" + student.getName() + " 课程:" + student.getCourseScoreList().get(0).getCourse().getCourseName() + " 分数:" + student.getCourseScoreList().get(0).getScore());
    32 
    33     }
    34 
    35 }

    //还是把day_8_mybatis.util.SessionFactory2代码贴出来吧,SqlSessionFactory用到了单例模式,这也是MyBatis官方文档所提倡的,具体可以移步之前写的几个关键类的作用域问题,《SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession作用域(Scope)和生命周期》,也可移步至《单例模式》《再说单例模式的线程安全问题》了解单例模式。

     1 package day_8_mybatis.util;
     2 
     3 import java.io.InputStream;
     4 
     5 import org.apache.ibatis.session.SqlSessionFactory;
     6 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
     7 
     8 /**
     9  * @author turbo
    10  *
    11  * 2016年10月26日
    12  */
    13 public class SessionFactory2 {
    14     private static SqlSessionFactory sqlSessionFactory;
    15     
    16     public static synchronized SqlSessionFactory getInstance(InputStream inputStream){
    17         if (null == sqlSessionFactory){
    18             sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    19         }
    20         
    21         return sqlSessionFactory;
    22     }
    23 }
  • 相关阅读:
    leetcode 47 Permutations II ----- java
    leetcode 46 Permutations ----- java
    leetcode 45 Jump Game II ---- java
    leetcode 44 Wildcard Matching ----java
    leetcode 43 Multiply Strings ----java
    leetcode 42 Trapping Rain Water ---java
    leetcode 41 First Missing Positive ---java
    leetcode 40 Combination Sum II --- java
    leetcode 39 Combination Sum --- java
    java 上下文切换
  • 原文地址:https://www.cnblogs.com/yulinfeng/p/6034256.html
Copyright © 2020-2023  润新知