Mybatis-查詢處理一對一和一對多

前期準備

數據庫資源準備:

CREATE DATABASE mybatis;

USE mybatis;

CREATE TABLE `teacher`(
 `id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '主鍵id',
 `name` VARCHAR (30) NOT NULL COMMENT '姓名'
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO teacher(`name`) VALUES ('胡老師');
INSERT INTO teacher(`name`) VALUES ('黃老師');

CREATE TABLE `student`(
 `id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '主鍵id',
 `name` VARCHAR (30) NOT NULL COMMENT '姓名',
 `tid` INT DEFAULT NULL,
 KEY `fktid`(`tid`),
 CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher`(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `student`( `name`,`tid`) VALUES ('小明',1);
INSERT INTO `student`( `name`,`tid`) VALUES ('小紅',1);
INSERT INTO `student`( `name`,`tid`) VALUES ('小剛',1);
INSERT INTO `student`( `name`,`tid`) VALUES ('小張',2);
INSERT INTO `student`( `name`,`tid`) VALUES ('小麗',2);
INSERT INTO `student`( `name`,`tid`) VALUES ('小美',2);

雖然只有簡單的兩個表,但是可以很明顯的反映一對一和一對多的情景。

在這裏插入圖片描述

如果學生對老師,就是一對一的情況,如果是老師對學生,就是一對多。
我們可以理解爲一個學生有一個老師,但是一個老師就包含多個學生。

這裏不再贅述Mybatis的配置,僅列出較爲重要的代碼。

一對一

這裏我們就以一個學生包含一個唯一的老師爲例:

需求:這裏我們需要查詢出學生的信息,其學生的信息包含老師的信息。

實體類如下(爲節省文章篇幅,省略了實體類的構造方法、getter、setter和toString):
Teacher類

package com.ara.pojo;

//老師
public class Teacher {

    private int id;
    private String name;
}
    

Student類

//學生
public class Student {

    private int id;
    private String name;

    //學生要關聯一個老師 一個學生對應一個老師
    private Teacher teacher;
}

TeacherMapper接口(由於這裏演示僅需要這一個方法,爲了簡便就直接使用註解了):

package com.ara.dao;

import com.ara.pojo.Teacher;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

public interface TeacherMapper {

    /**
     * 通過老師的id查詢出老師的信息
     *
     * @param id 老師的唯一主鍵id
     * @return 返回id對應的老師信息
     */
    @Select("select * from teacher where id = #{id}")
    Teacher getTeacherById(@Param("id") int id);

}

StudentMapper接口:

package com.ara.dao;

import com.ara.pojo.Student;
import org.apache.ibatis.annotations.Param;

public interface StudentMapper {

   /**
     * 根據學生的主鍵id查詢學生的詳細信息 其中包含老師的信息
     * 方式一
     *
     * @param id 主鍵id
     * @return 返回對應的學生信息
     */
    Student getStudentById1(@Param("id") int id);

    /**
     * 根據學生的主鍵id查詢學生的詳細信息 其中包含老師的信息
     * 方式二
     *
     * @param id 主鍵id
     * @return 返回對應的學生信息
     */
    Student getStudentById2(@Param("id") int id);


}

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.ara.dao.StudentMapper">

    <!--  直接使用聯表查詢 start  -->
    <select id="getStudentById1" parameterType="_int" resultMap="StudentMap1">
        select s.id sid,s.name sname,t.id tid,t.name tname from student s,teacher t where s.tid = t.id and s.id = #{id};
    </select>
    <resultMap id="StudentMap1" type="Student">
        <result column="sid" property="id" />
        <result column="sname" property="name" />
        <!--
            由於這裏屬於嵌套組合的屬性 我們採用association標籤
            因爲我們需要對Student中Teacher進行再次封裝 所以我們需要制定如下屬性
                property:Student類中的屬性名
                javaType:制定屬性的Java類型
        -->
        <association property="teacher" javaType="Teacher">
            <result column="tid" property="id" />
            <result column="tname" property="name" />
        </association>
    </resultMap>
    <!--  方式一:直接使用聯表查詢 end  -->


    <!--  方式二:查詢中嵌套查詢 start  -->
    <select id="getStudentById2" parameterType="_int" resultMap="StudentMap2">
        select * from student where id = #{id};
    </select>
    <resultMap id="StudentMap2" type="Student">
        <result column="id" property="id" />
        <result column="name" property="name" />
        <!--
            由於這裏屬於分兩次查詢 所以我們直接利用外鍵這列來查詢Teacher信息
                column:查詢後的列名
                property:Student類中的屬性名
                javaType:制定屬性的Java類型
                select:需要引用的查詢Id
        -->
        <association column="tid" property="teacher" javaType="Teacher" select="com.ara.dao.TeacherMapper.getTeacherById"/>
    </resultMap>
    <!--  方式二:查詢中嵌套查詢 end  -->

</mapper>

測試代碼:

package com.ara.test;

import com.ara.dao.StudentMapper;
import com.ara.pojo.Student;
import com.ara.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class StudentMapperTest {

    @Test
    public void getStudentByIdTest1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        Student student = studentMapper.getStudentById1(1);
        System.out.println(student);

        sqlSession.close();
    }

    @Test
    public void getStudentByIdTest2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        Student student = studentMapper.getStudentById2(5);
        System.out.println(student);

        sqlSession.close();
    }

}

getStudentByIdTest1結果:
在這裏插入圖片描述
getStudentByIdTest2結果:
在這裏插入圖片描述

兩種方式都可以查詢出結果,但是兩者的過程並不相同,聯表查詢雖然SQL語句較爲複雜,但是它的執行就只運行了一條SQL語句,嵌套查詢雖然SQL語句簡單,但是它卻執行了兩個SQL語句,具體開發中,還是要根據自己的需要來酌情選擇。

一對多

這裏我們就以一個老師有多個學生爲例:

需求:根據對應老師的Id查詢老師的信息及其所有的學生信息。

實體類如下(爲節省文章篇幅,省略了實體類的構造方法、getter、setter和toString):

Student類:

package com.ara.pojo;

//學生類
public class Student {

    private int id;
    private String name;
    //學生要關聯一個老師id
    private int tid;
    
}

Teacher類:

package com.ara.pojo;

import java.util.List;

//老師
public class Teacher {

    private int id;
    private String name;

    //老師含有多個學生
    private List<Student> students;

}

StudentMapper接口:

package com.ara.dao;


import com.ara.pojo.Student;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface StudentMapper {

    /**
     * 老師的id查詢其學生列表
     * @param tid 老師id
     * @return 返回學生列表
     */
    @Select("select * from student where tid = #{tid}")
    List<Student> getStudentByTId(@Param("tid")int tid);

}

TeacherMapper接口:

package com.ara.dao;

import com.ara.pojo.Teacher;
import org.apache.ibatis.annotations.Param;

public interface TeacherMapper {

    /**
     * 根據教師的id查詢教師的信息 包含其名下學生信息
     * 方式一
     *
     * @param id 教師id
     * @return 返回對應教師的信息
     */
    Teacher getTeacherById1(@Param("id") int id);

    /**
     * 根據教師的id查詢教師的信息 包含其名下學生信息
     * 方式二
     *
     * @param id 教師id
     * @return 返回對應教師的信息
     */
    Teacher getTeacherById2(@Param("id") int id);

}

TeacherMapper.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.ara.dao.TeacherMapper">
   <!--  方式一:結果嵌套查詢 start  -->
    <select id="getTeacherById1" parameterType="_int" resultMap="teacherInfoMap1">
        select t.id tid,t.name tname,s.id sid,s.name sname from teacher t,Student s where t.id = s.tid and t.id = #{id}
    </select>
    <resultMap id="teacherInfoMap1" type="Teacher">
        <result column="tid" property="id" />
        <result column="tname" property="name" />
        <!--
            複雜的屬性 我們需要單獨處理 集合使用collection
            javaType:指定屬性的類型
            ofType:指定集合中的泛型信息
        -->
        <collection property="students" ofType="Student" >
            <result column="sid" property="id" />
            <result column="sname" property="name" />
            <result column="tid" property="tid" />
        </collection>
    </resultMap>
    <!--  方式一:結果嵌套查詢 end  -->


    <!--  方式二:查詢嵌套查詢 start  -->
    <select id="getTeacherById2" parameterType="_int" resultMap="teacherInfoMap2" >
        select * from teacher where id = #{id};
    </select>
    <resultMap id="teacherInfoMap2" type="Teacher">
        <result column="id" property="id" />
        <result column="name" property="name" />
        <!--
            複雜的屬性 我們需要單獨處理 集合使用collection
                column:指定需要再次查詢的列名
                property:指定Teacher中的students屬性
                javaType:指定Teacher中的students屬性的Java類型
                ofType:指定Teacher中的students屬性的Java類型的泛型類型
                select:指定我們需要做再次查詢的方法id
        -->
        <collection column="id" property="students" javaType="ArrayList" ofType="Student" select="com.ara.dao.StudentMapper.getStudentByTId"/>
    </resultMap>
    <!--  方式二:查詢嵌套查詢 end  -->

</mapper>

測試代碼如下:

package com.ara.dao.test;

import com.ara.dao.TeacherMapper;
import com.ara.pojo.Teacher;
import com.ara.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class TeacherMapperTest {

    @Test
    public void getTeacherByIdTest1(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();

        Teacher teacher = sqlSession.getMapper(TeacherMapper.class).getTeacherById1(1);

        System.out.println(teacher);

        sqlSession.close();

    }

    @Test
    public void getTeacherByIdTest2(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();

        Teacher teacher = sqlSession.getMapper(TeacherMapper.class).getTeacherById2(2);

        System.out.println(teacher);

        sqlSession.close();

    }

}

getTeacherByIdTest1測試結果:

在這裏插入圖片描述

getTeacherByIdTest2測試結果:
在這裏插入圖片描述

這兩種方式都能實現我們的需求,但是也存在着上述一對一的情況,就是聯表查詢的SQL語句雖然較爲複雜,但是它只運行了一條SQL,通過查詢中嵌套查詢,雖然SQL簡單了,但是它分了兩條SQL進行查詢。

都各有優缺點,結果中嵌套只是理解起來可能較爲複雜,但是它的效率就相對較高,查詢中嵌套查詢,雖然SQL語句很簡單,但是它的執行效率就相對來說較爲低下。

實際的開發中,根據具體的情況具體斟酌即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章