亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

MyBatis之級聯(lián)——一對多關(guān)系

原創(chuàng) 2016-11-07 11:53:08 627
摘要:上次我們講到了MyBatis的一對一關(guān)系的表示,簡單回顧一下一對一關(guān)系就是一個學(xué)生只有一個學(xué)生證。那么什么是一對多關(guān)系呢?一個學(xué)生有多個課程這就是一對多的關(guān)系。我們結(jié)合上一章中的學(xué)生和學(xué)生證,在此基礎(chǔ)上新增一個課程表和課程成績表。學(xué)生對應(yīng)課程表是一對多的關(guān)系,在學(xué)生確定的情況下課程表對應(yīng)課程成績是一對一的關(guān)系。我們先來看看我們所假設(shè)的場景數(shù)據(jù)結(jié)構(gòu)的設(shè)計。數(shù)據(jù)庫的ER圖如下(因?yàn)閷?shù)據(jù)庫還處于菜鳥階

上次我們講到了MyBatis的一對一關(guān)系的表示,簡單回顧一下一對一關(guān)系就是一個學(xué)生只有一個學(xué)生證。那么什么是一對多關(guān)系呢?一個學(xué)生有多個課程這就是一對多的關(guān)系。我們結(jié)合上一章中的學(xué)生和學(xué)生證,在此基礎(chǔ)上新增一個課程表和課程成績表。學(xué)生對應(yīng)課程表是一對多的關(guān)系,在學(xué)生確定的情況下課程表對應(yīng)課程成績是一對一的關(guān)系。我們先來看看我們所假設(shè)的場景數(shù)據(jù)結(jié)構(gòu)的設(shè)計。

數(shù)據(jù)庫的ER圖如下(因?yàn)閷?shù)據(jù)庫還處于菜鳥階段……所以可能ER圖繪制有誤,但不影響我們講解MyBatis一對多關(guān)系的級聯(lián)):

31.png


再看看數(shù)據(jù)庫的物理模型包含哪些字段:


 32.png

數(shù)據(jù)庫的設(shè)計就差不多了,接下來是設(shè)計我們的POJO類:

首先是Student類:

package day_8_mybatis.pojo;
import java.util.List;
  /**
  * @author turbo
  *
  * 2016年11月4日
  */
 public class Student {
     private int id;
     private String name;
     private String sex;
     private SelfCard selfCard;  //學(xué)生和學(xué)生證是一對一的關(guān)系,所以存放一個對學(xué)生證類的引用
     private List<CourseScore> courseScoreList;  //我們在一開始就提到過學(xué)生和課程是一對多的關(guān)系,所以學(xué)生POJO類中對課程類字段就是一個List用來存放學(xué)生的課程成績。
     //省略set/get方法      
 }

注意,我們有一個List字段是對課程成績的引用而不是課程的引用。為什么呢?因?yàn)樵谖覀償?shù)據(jù)庫設(shè)計中,學(xué)生和課程是通過課程成績聯(lián)系起來的。

接著是我們的CourseScore類:

package day_8_mybatis.pojo;
/**
 * @author turbo
  *
  * 2016年11月4日
  */
 public class CourseScore {
     private int id;
     private int studentId;
     private Course course;  //在學(xué)生id確認(rèn)的情況下,課程和成績是一對一的關(guān)系。
     private String score;
     //省略set/get方法  
 }

最后是Course類:

package day_8_mybatis.pojo;
 /**
 * @author turbo
 *
 * 2016年11月4日
 */
 public class Course {
     private int id;
     private String courseName;
     private String note;
     //省略set/get方法
 }

現(xiàn)在我們是要通過一個學(xué)生ID,就能查詢出這個學(xué)生的課程、以及對應(yīng)課程的成績。這個怎么來實(shí)現(xiàn)呢?在使用MyBatis為我們提供的級聯(lián)前,我們先來梳理一下從邏輯上是怎么一步一步查詢出來的。

我們要通過學(xué)生id查詢出學(xué)生的基本信息(包括課程以及對應(yīng)的成績),但在學(xué)生POJO類中有一個對課程成績的List引用(暫時忽略學(xué)生證),也就是說我們無法一條簡單的sql語句(無join的sql語句)查詢出結(jié)果。但是!我們可以通過student_id在課程成績表中查詢出該學(xué)生的相應(yīng)課程id(注意此時還是id),但我們此時還是沒辦法知道具體的課程名,再利用我們上一步中student_id查詢出的course_id通過課程表再來查詢出對應(yīng)的課程名。重新梳理一下:

  • 通過student_id在t_student表中查詢學(xué)生基本信息(name,sex)

  • 通過student_id在t_course_score表中查詢學(xué)生對應(yīng)的course_id

  • 通過course_id在t_course表中查詢課程

那我們現(xiàn)在就從最底層做起,也就是通過course_id查詢出具體課程,因?yàn)檫@不會涉及到其他表。

 package day_8_mybatis.mapper; 
 import day_8_mybatis.pojo.Course; 
 /**
  * @author turbo
  *
  * 2016年11月4日
  */
 public interface CourseMapper {
     Course getCourse(int id);  //此id為course_id
 }

再來看看mapper映射,也是非常簡單。

 <?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="day_8_mybatis.mapper.CourseMapper">
     <select id="getCourse" parameterType="int" resultType="day_8_mybatis.pojo.Course">
         select id, course_name as courseName, note from t_course where id = #{id}
     </select>
 </mapper>

現(xiàn)在已經(jīng)寫好了通過course_id來查詢出具體課程。那么就是倒著走到第2步,通過student_id在t_course_score表中查詢學(xué)生對應(yīng)的course_id,在最開始說過,在學(xué)生確定的情況下,課程和課程成績是一對一的關(guān)系,關(guān)于一對一的關(guān)系我們在上一篇已經(jīng)講過,不妨再重溫一下。

 package day_8_mybatis.mapper;
 
 import day_8_mybatis.pojo.CourseScore;
 
 /**
  * @author turbo
  *
  * 2016年11月4日
  */
 public interface CourseScoreMapper {
     CourseScore findCourseScoreByStudentId(int id);
 }

再來看看mapper映射,也是非常簡單。

 <?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="day_8_mybatis.mapper.CourseScoreMapper">
     <resultMap id="courseScoreMap" type="day_8_mybatis.pojo.CourseScore">
         <id property="id" column="id"/>
         <result property="studentId" column="student_id"/>
         <result property="score" column="score"/>
         <association property="course" column="course_id" select="day_8_mybatis.mapper.CourseMapper.getCourse" />  <!--將查詢出來的course_id交給CouseMapper來查詢出具體課程信息-->
     </resultMap>
     
     <select id="findCourseScoreByStudentId" parameterType="int" resultMap="courseScoreMap">
         select id, student_id, course_id, score from t_course_score where student_id = #{id}
     </select>
 </mapper>

最后一步,也就是第1步,才進(jìn)入正題MyBatis的一對多collection級聯(lián)關(guān)系。

 package day_8_mybatis.mapper;
 
 import day_8_mybatis.pojo.Student;
 
 /**
  * @author turbo
  *
  * 2016年11月4日
  */
 public interface StudentMapper {
     Student getStudent(int id);
 }

關(guān)鍵在mapper映射中。

 <?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="day_8_mybatis.mapper.StudentMapper">
     <resultMap type="day_8_mybatis.pojo.Student" id="studentMap">
         <id property="id" column="id"/>
         <result property="name" column="name"/>
         <result property="sex" column="sex"/>
         <association property="selfCard" column="id" select="day_8_mybatis.mapper.SelfCardMapper.findSelfCardByStudentId"/>
         <collection property="courseScoreList" column="id" select="day_8_mybatis.mapper.CourseScoreMapper.findCourseScoreByStudentId" />
         </resultMap>
     <select id="getStudent" parameterType="int" resultMap="studentMap">
         select id, name, sex from t_student where id = #{id}
     </select>
 </mapper>

請好好仔細(xì)品味品味,仔細(xì)回顧整個查詢的邏輯過程。collection就是MyBatis為我們提供的第二個級聯(lián)關(guān)系——一對多。

最后上我們的測試代碼:

 package day_8_mybatis;
 
 import java.io.IOException;
 import java.io.InputStream;
 
 import org.apache.ibatis.io.Resources;
 import org.apache.ibatis.session.SqlSession;
 
 import day_8_mybatis.mapper.StudentMapper;
 import day_8_mybatis.pojo.Student;
 import day_8_mybatis.util.SessionFactory2;
 
 /**
  * 客戶端
  * @author turbo
  *
  * 2016年11月4日
  */
 public class Main {
 
     /**
      * @param args
      * @throws IOException 
      */
     public static void main(String[] args) throws Exception {
         String resource = "day_8_mybatis/mybatis-config.xml";        //獲取mybatis配置文件路徑
         InputStream inputStream = Resources.getResourceAsStream(resource);
         SqlSession sqlSession = SessionFactory2.getInstance(inputStream).openSession();
         StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
         Student student = studentMapper.getStudent(1);
         System.out.println("學(xué)生:" + student.getName() + " 課程:" + student.getCourseScoreList().get(0).getCourse().getCourseName() + " 分?jǐn)?shù):" + student.getCourseScoreList().get(0).getScore());
 
     }
 
 }

//還是把day_8_mybatis.util.SessionFactory2代碼貼出來吧,SqlSessionFactory用到了單例模式,這也是MyBatis官方文檔所提倡的,具體可以移步之前寫的幾個關(guān)鍵類的作用域問題,《SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession作用域(Scope)和生命周期》,也可移步至《單例模式》、《再說單例模式的線程安全問題》了解單例模式。

 package day_8_mybatis.util;
 
 import java.io.InputStream;
 
 import org.apache.ibatis.session.SqlSessionFactory;
 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 
 /**
  * @author turbo
  *
  * 2016年10月26日
  */
 public class SessionFactory2 {
     private static SqlSessionFactory sqlSessionFactory;
     
     public static synchronized SqlSessionFactory getInstance(InputStream inputStream){
         if (null == sqlSessionFactory){
             sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
         }
         
         return sqlSessionFactory;
     }
 }
發(fā)布手記

熱門詞條