Mybatis关联映射 多表查询(三种写法优缺点、主流性) 以及分步查询 延迟加载(按需加载、懒加载)

Mybatis关联映射


真是保姆级的教程,因为我很菜。。。主要是给自己反复看的,所以非常非常详


目录

一、创建表结构

一对多、多对一 (以查询学生的老师为例)三种写entity层的方式

第一种:设置联合的实体类(不常用)

第二种:连表查询

三、分步查询

一对多(以查询老师的学生为例)

一、关联映射

二、分步查询

多对多

例1.查询老师上课的班级

例2.查询班级的老师

 实现延迟加载以及一些对比


一、创建表结构

我的MySQL表

student表

 teacher表

 mybatis配置问题这里就不提了,主要是记录一下mybatis的关联映射,方便我以后自己看

关联查询

一对多、多对一 (以查询学生的老师为例)三种写entity层的方式

第一种:设置联合的实体类(不常用)

新建一个StudentTeacher关联实体类

package com.qcby.entity;

//这样做 只能查询 不能增删改查 无法做一些关联性的东西
public class StudentTeacher {
    private Integer SId;//学生的数据
    private String Sname;
    private String sex;
    private Integer age;
    private Integer t_id;
    private Integer TId;
    private String Tname;

    public Integer getSId() {
        return SId;
    }

    public void setSId(Integer SId) {
        this.SId = SId;
    }

    public String getSname() {
        return Sname;
    }

    public void setSname(String sname) {
        Sname = sname;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getT_id() {
        return t_id;
    }

    public void setT_id(Integer t_id) {
        this.t_id = t_id;
    }

    public Integer getTId() {
        return TId;
    }

    public void setTId(Integer TId) {
        this.TId = TId;
    }

    public String getTname() {
        return Tname;
    }

    public void setTname(String tname) {
        Tname = tname;
    }

    @Override
    public String toString() {
        return "StudentTeacher{" +
                "SId=" + SId +
                ", Sname='" + Sname + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                ", t_id=" + t_id +
                ", TId=" + TId +
                ", Tname='" + Tname + '\'' +
                '}';
    }
}

新建StudentTeacher Dao层接口

新建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="com.qcby.dao.StudentTeacherDao">
<!--映射-->
    <resultMap id="getStudentTeacher" type="com.qcby.entity.StudentTeacher"><!--type做具体映射-->
        <!--数据库关联映射-->
        <result column="id" property="SId"/>
        <result column="Sname" property="Sname"/>
        <result column="Tname" property="Tname"/>
    </resultMap>

    <select id="getStudentTeacher" resultMap="getStudentTeacher">
        select student.id,student.Sname,teacher.Tname from student left join teacher on student.t_id = teacher.id;
    </select>
</mapper>

resultMap做映射,在数据库学生表中id为id ,但是实体层我们定义的是SId 

property:属性=>对应就是java类中的属性,也就是类中定义的字段;

column =>对应就是数据库表中的字段。

resultMap中的type要连接实体类

然后sql语句的标签中id要跟resultMap 的 id 一致

另一个属性是resultMap,不要写resultType

然后在Dao层去给方法定义

package com.qcby.dao;

import com.qcby.entity.StudentTeacher;

import java.util.List;

public interface StudentTeacherDao {
    List<StudentTeacher> getStudentTeacher();
}

在SqlMapConfig.xml中要映射

 最后写Test类进行测试

package com.qcby;

import com.qcby.dao.StudentTeacherDao;
import com.qcby.entity.StudentTeacher;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class StudentTeacherDaoTest {
    private InputStream in = null;
    private SqlSession session = null;
    private StudentTeacherDao mapper = null;

    @Before  //前置通知, 在方法执行之前执行
    public void init() throws IOException {
        //加载主配置文件,目的是为了构建SqlSessionFactory对象
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //通过SqlSessionFactory工厂对象创建SqlSesssion对象
        session = factory.openSession(true);  //关闭
        //通过Session创建UserDao接口代理对象
        mapper = session.getMapper(StudentTeacherDao.class);
    }

    @After  //@After: 后置通知, 在方法执行之后执行 。
    public void destory() throws IOException {
        //释放资源
        session.close();
        in.close();
    }
    @Test
    public void StudentTeacherDao(){
        List<StudentTeacher> studentTeachers = mapper.getStudentTeacher();
        for (StudentTeacher  s:studentTeachers){
            System.out.println(s.toString());
        }
    }

}

运行test 可以看到控制台查询到的结果

 我们发现一个问题,这样做单独建了一个StudentTeacher实体类

但是这个表只可以做一个查询,没有太多的操作空间

一般表有哪些,就应该有哪些实体类

第二种:连表查询

我们新建表的实体类

学生的实体类

package com.qcby.entity;

public class Student {
    private Integer id;
    private String Sname;
    private String sex;
    private Integer age;
    private Integer t_id;

    //学生当中包含老师
     private Teacher teacher;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getSname() {
        return Sname;
    }

    public void setSname(String sname) {
        Sname = sname;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getT_id() {
        return t_id;
    }

    public void setT_id(Integer t_id) {
        this.t_id = t_id;
    }

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", Sname='" + Sname + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                ", t_id=" + t_id +
                ", teacher=" + teacher +
                '}';
    }
}

这里不要忘记加上老师 这个对象

学生和老师是多对一的关系

在学生表中写一个teacher类 学生中包含着老师

Teacher类

package com.qcby.entity;

public class Teacher {
    private Integer id;
    private String Tname;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTname() {
        return Tname;
    }

    public void setTname(String tname) {
        Tname = tname;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", Tname='" + Tname + '\'' +
                '}';
    }
}

新建一个学生的StudentDao

在mapper中新建StudentDao.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.qcby.dao.StudentDao">
    <!---->

    <select id="getStudentTeacher1" resultMap="StudentTeacher1">
        select student.id,student.Sname,teacher.Tname from student left join teacher on student.t_id = teacher.id;
    </select>
    <resultMap id="StudentTeacher1" type="com.qcby.entity.Student">
        <result property="id" column="id"/>
        <result property="Sname" column="Sname"/>
        <result property="sex" column="sex"/>
        <result property="age" column="age"/>
        <result property="t_id" column="t_id"/>
        <!--复杂属性单独处理 对象用association-->
        <!--javaType:该属性的类型-->
        <association property="teacher" javaType="com.qcby.entity.Teacher">
            <result property="id" column="id"/>
            <result property="Tname" column="Tname"/>
        </association>
    </resultMap>
</mapper>

特殊属性特殊处理,我们在创建entity层Student的实体类时,定义了Teacher类

这里应该用<association>标签进行处理

接下来通过Test测试一下

编写StudentDao层

package com.qcby.dao;

import com.qcby.entity.Student;

import java.util.List;

public interface StudentDao {
    List<Student> getStudentTeacher1();
}

编写StudentDaoTest测试

package com.qcby;

import com.qcby.dao.StudentDao;
import com.qcby.entity.Student;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class StudentDaoTest {
    private InputStream in = null;
    private SqlSession session = null;
    private StudentDao mapper = null;

    @Before  //前置通知, 在方法执行之前执行
    public void init() throws IOException {
        //加载主配置文件,目的是为了构建SqlSessionFactory对象
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //通过SqlSessionFactory工厂对象创建SqlSesssion对象
        session = factory.openSession(true);  //关闭
        //通过Session创建UserDao接口代理对象
        mapper = session.getMapper(StudentDao.class);
    }

    @After  //@After: 后置通知, 在方法执行之后执行 。
    public void destory() throws IOException {
        //释放资源
        session.close();
        in.close();
    }
@Test
    public void getStudentTeacher1(){
        List<Student> studentTeachers1 = mapper.getStudentTeacher1();
        for (Student s:studentTeachers1){
            System.out.println(s.toString());
        }

    }

}

测试前注意一下SqlMapConfig.xml中有没有映射到Dao层,

<mappers>
        <mapper resource="mapper/StudentDao.xml"/>
</mappers>

如果没有映射到,是无法加载到的。

通过Test运行测试 成功查询到了每个学生的老师的信息

三、分步查询

编写StudentDao.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.qcby.dao.StudentDao">
    <!--分步查询-->
    <select id="getStudent" resultMap="StudentTeacher2">
        select * from student;
    </select>
        <resultMap id="StudentTeacher2" type="com.qcby.entity.Student">
            <result property="id" column="id"/>
            <result property="Sname" column="Sname"/>
            <result property="sex" column="sex"/>
            <result property="age" column="age"/>
            <result property="t_id" column="t_id"/>
            <!--column:传值-->
            <!--select:调用-->
            <association property="teacher" javaType="com.qcby.entity.Teacher"
                         column="t_id" select="getTeacher"/>
        </resultMap>
        <select id="getTeacher" resultType="com.qcby.entity.Teacher">
            select teacher.Tname from teacher where id = #{id}
        </select>
</mapper>

column是用来传值的,select是调用的,里面填写select的语句标签的id

编写Dao层的StudentDao接口

package com.qcby.dao;

import com.qcby.entity.Student;

import java.util.List;

public interface StudentDao {

    List<Student> getStudent();
}

最后再写Test 来进行测试

package com.qcby;

import com.qcby.dao.StudentDao;
import com.qcby.entity.Student;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class StudentDaoTest {
    private InputStream in = null;
    private SqlSession session = null;
    private StudentDao mapper = null;

    @Before  //前置通知, 在方法执行之前执行
    public void init() throws IOException {
        //加载主配置文件,目的是为了构建SqlSessionFactory对象
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //通过SqlSessionFactory工厂对象创建SqlSesssion对象
        session = factory.openSession(true);  //关闭
        //通过Session创建UserDao接口代理对象
        mapper = session.getMapper(StudentDao.class);
    }

    @After  //@After: 后置通知, 在方法执行之后执行 。
    public void destory() throws IOException {
        //释放资源
        session.close();
        in.close();
    }

    @Test
    public void getStudent(){
        List<Student> studentTeachers1 = mapper.getStudent();
        for (Student student:studentTeachers1){
            System.out.println(student.getSname());//查询学生的名字(跟老师没关系)
        }

    }

}

运行测试

我们可以看到以下结果

StudentDao.xml的

这句话其实可以新建一个TeacherDao.xml写在里面 做一个单独的存在

这样做的好处就是两条sql语句都可以单独的出现

在Dao层新建TeacherDao

在mapper中新建TeacherDao.xml

然后做定义 select id为getTeacherById

<?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.qcby.dao.TeacherDao">

    <select id="getTeacherById" resultType="com.qcby.entity.Teacher" parameterType="java.lang.Integer">
        select * from teacher where id = #{t_id}
    </select>
</mapper>

在dao层中进行调用具体实现

package com.qcby.dao;

import com.qcby.entity.Teacher;

import java.util.List;

public interface TeacherDao {
    public Teacher getTeacherById(Integer id);
}

进行改动过后,我们StudentDao.xml 中的select调用也要进行改变

这里就不能再写getTeacher了,改成刚定义的getTeacherById

注意:select里用是dao层 

Test测试中不用进行改变,我们进行测试,结果如下

 可以看到,分步查询正常测试出来了

把sql语句单独体现在TeacherDao 中,我们也可以新建一个TeacherTest测试,进行单独调用

新建TeacherDao

package com.qcby.dao;

import com.qcby.entity.Teacher;


public interface TeacherDao {
    public Teacher getTeacherById(Integer id);
}

Test测试

package com.qcby;

import com.qcby.dao.TeacherDao;
import com.qcby.entity.Teacher;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class TeacherDaoTest {
    private InputStream in = null;
    private SqlSession session = null;
    private TeacherDao mapper = null;

    @Before  //前置通知, 在方法执行之前执行
    public void init() throws IOException {
        //加载主配置文件,目的是为了构建SqlSessionFactory对象
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //通过SqlSessionFactory工厂对象创建SqlSesssion对象
        session = factory.openSession(true);  //关闭
        //通过Session创建UserDao接口代理对象
        mapper = session.getMapper(TeacherDao.class);
    }

    @After  //@After: 后置通知, 在方法执行之后执行 。
    public void destory() throws IOException {
        //释放资源
        session.close();
        in.close();
    }
    @Test
    public void getTeacherById(){
       Teacher teacherById = mapper.getTeacherById(1);
        System.out.println(teacherById.toString());
    }
}

查询id为1的老师来测试

运行,结果如下

相当于一个参数两用,自身也可以进行使用,相当于这个sql语句可以进行重复性使用 

以上有两种写法来表示查询信息,分别是连表查询和分步查询的方法。那么既然我么能用一个SQL语句能够执行完,那为什么还要分开来写呢?

原因很简单:可以发现如果我们把他们连在一起那么他们就是一个多表查询语句,如果不放在一起执行,那那就是单独一个表的查询语句。

分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息

一对多(以查询老师的学生为例)

一个老师有多个学生,意味着一个老师有多个对象

在Teacher实体类中定义一个List集合 重新get set tostring方法

一、关联映射

entity层的Teacher类

package com.qcby.entity;

import java.util.List;

public class Teacher {
    private Integer id;
    private String Tname;
    List<Student> students;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTname() {
        return Tname;
    }

    public void setTname(String tname) {
        Tname = tname;
    }

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", Tname='" + Tname + '\'' +
                ", students=" + students +
                '}';
    }
}

编写mapper中的TeacherDao.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.qcby.dao.TeacherDao">

    <select id="getTeacher" resultMap="TeacherStudent">
        select teacher.*,student.Sname from teacher left join student on student.t_id = teacher.id
    </select>
    <resultMap id="TeacherStudent" type="com.qcby.entity.Teacher">
        <result property="id" column="id"/>
        <result property="Tname" column="Tname"/>
        <!--复杂字段特殊处理,对象用association 集合用collection-->
        <!--ofType:集合中泛型的信息 这里写students的类型-->
        <collection property="students" ofType="com.qcby.entity.Student">
            <!--只查询出来学生的名字,可以只写Sname-->
            <result property="Sname" column="Sname"/>
        </collection>
    </resultMap>
</mapper>

在Dao层的TeacherDao中添加方法

package com.qcby.dao;

import com.qcby.entity.Teacher;

import java.util.List;


public interface TeacherDao {
    public Teacher getTeacherById(Integer id);

    public List<Teacher> getTeacher();
}

写一个测试方法进行测试

@Test
    public void getTeacher(){
        List<Teacher> teachers = mapper.getTeacher();
        for (Teacher teacher:teachers){
            System.out.println(teacher.toString());
        }
    }

测试通过,输出结果

 老师下的所有 学生都被输出了出来,通过测试

因为只查询了Sname,所以其他字段显示为null

二、分步查询

先查询老师,根据老师的id去匹配学生的t_id 字段

1.select * from teacher;

2.select * from student where t_id = #{id}

写TeacherDao.xml

 <select id="getTeacher1" resultMap="TeacherStudent1">
        select * from teacher;
    </select>
    <resultMap id="TeacherStudent1" type="com.qcby.entity.Teacher">
        <result property="id" column="id"/>
        <result property="Tname" column="Tname"/>
        <collection property="students" ofType="com.qcby.entity.Student"
                    column="id" select="getStudntByTid"/>
    </resultMap>
    <select id="getStudntByTid" resultType="com.qcby.entity.Student">
        select * from student where t_id = #{id};
    </select>

配置dao层的TeacherDao

public List<Teacher> getTeacher1();

新建Test测试进行测试

@Test
    public void getTeacher1(){
        List<Teacher> teachers = mapper.getTeacher1();
        for (Teacher teacher:teachers){
            System.out.println(teacher.toString());
        }
    }

输出结果

老师所有的学生都成功被输出

当然我们也可以进行改进,将第二个sql语句放在StudentDao.xml里

并在Dao层的StudentDao中进行使用返回Student对象

Student getStudentByTid(Integer tid);

调用的配置进行修改

 测试发现依旧能通过测试

多对多

这里有两个例子,一个是查询老师教的班级,一个是班级的授课老师

例如教师和授课班级之间的关系,甲乙丙三个老师分别教ABC三个班

多对多一般用分步的形式

因为组合形式sql太大,影响我们的执行时间

我们先创建一个班级表

 再建一个老师班级关系表

c_id 班级id

t_id 教师id

分步实现

例1.查询老师上课的班级

1.select * from teacher ;//查询出老师的id

2.匹配查询,让班级和关系表关联查询

select classes.id,classes.className,rel.t_id from classes left join rel on rel.c_id = classes. id where t_id = #{id}

用Mybatis实现

新建Classes实体类

package com.qcby.entity;

import java.util.Date;

public class Classes {
    private Integer id;
    private String classesName;
    private Date creatTime;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getClassesName() {
        return classesName;
    }

    public void setClassesName(String classesName) {
        this.classesName = classesName;
    }

    public Date getCreatTime() {
        return creatTime;
    }

    public void setCreatTime(Date creatTime) {
        this.creatTime = creatTime;
    }

    @Override
    public String toString() {
        return "Classes{" +
                "id=" + id +
                ", classesName='" + classesName + '\'' +
                ", creatTime=" + creatTime +
                '}';
    }
}

新建rel实体类

package com.qcby.entity;

public class RelationShip {
    private Integer id;
    private Integer t_id;
    private Integer c_id;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getT_id() {
        return t_id;
    }

    public void setT_id(Integer t_id) {
        this.t_id = t_id;
    }

    public Integer getC_id() {
        return c_id;
    }

    public void setC_id(Integer c_id) {
        this.c_id = c_id;
    }

    @Override
    public String toString() {
        return "RelationShip{" +
                "id=" + id +
                ", t_id=" + t_id +
                ", c_id=" + c_id +
                '}';
    }
}

查询老师教的班级,主体在老师当中

更改Teacher实体类

package com.qcby.entity;

import java.util.List;

public class Teacher {
    private Integer id;
    private String Tname;
    private List<Classes> classes;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTname() {
        return Tname;
    }

    public void setTname(String tname) {
        Tname = tname;
    }

    public List<Classes> getClasses() {
        return classes;
    }

    public void setClasses(List<Classes> classes) {
        this.classes = classes;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", Tname='" + Tname + '\'' +
                ", classes=" + classes +
                '}';
    }
    
}

编写TeacherDao.xml

<select id="getTeacherClasses" resultMap="TeacherClasses">
        select * from teacher;
    </select>
    <resultMap id="TeacherClasses" type="com.qcby.entity.Teacher">
        <result property="id" column="id"/>
        <result property="Tname" column="Tname"/>
        <collection property="classes" ofType="com.qcby.entity.Classes" column="id" select="getClassesByTeacher"/>
    </resultMap>
    <select id="getClassesByTeacher" resultType="com.qcby.entity.Classes">
        select classes.id,classes.className,rel.t_id from classes left join rel on rel.c_id = classes.id where t_id = #{id}
    </select>

在Dao层实现

public List<Teacher> getTeacherClasses();

编写测试

@Test
    public void getClassesByTeacher(){
        List<Teacher> teacherClasses = mapper.getTeacherClasses();
        for(Teacher teacher:teacherClasses){
            System.out.println(teacher.toString());
        }
    }

运行测试结果如下

改进

将第二步分开

新建一个RelationShipDao

将dao层放进config里

然后在Dao层新建一个RelationShipDao.xml

 将第二步sql语句拿过来

<?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.qcby.dao.RelationShipDao">
    <select id="getClassesByTeacher" resultType="com.qcby.entity.Classes">
        select classes.id,classes.className,rel.t_id from classes left join rel on rel.c_id = classes.id where t_id = #{id}
    </select>
</mapper>

 改变TeacherDao.xml 中的select

 在Dao层实现

package com.qcby.dao;

import com.qcby.entity.Classes;

import java.util.List;

public interface RelationShipDao {
   List<Classes> getClassesByTeacher();
}

运行Test方法进行测试 正常输出

例2.查询班级的老师

1.select * from classes

2.select teacher.* from teacher left join rel on rel.t_id = teacher.id where c_id = #{id}

新建ClassesDao.xml

在Classes实体类中添加老师类,重写get set tostring方法

package com.qcby.entity;

import java.util.Date;
import java.util.List;

public class Classes {
    private Integer id;
    private String classesName;
    private Date creatTime;

    private List<Teacher> teachers;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getClassesName() {
        return classesName;
    }

    public void setClassesName(String classesName) {
        this.classesName = classesName;
    }

    public Date getCreatTime() {
        return creatTime;
    }

    public void setCreatTime(Date creatTime) {
        this.creatTime = creatTime;
    }

    public List<Teacher> getTeachers() {
        return teachers;
    }

    public void setTeachers(List<Teacher> teachers) {
        this.teachers = teachers;
    }

    @Override
    public String toString() {
        return "Classes{" +
                "id=" + id +
                ", classesName='" + classesName + '\'' +
                ", creatTime=" + creatTime +
                ", teachers=" + teachers +
                '}';
    }
}

编写ClassesDao.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.qcby.dao.ClassesDao">
    <select id="getClassesTeacher" resultMap="ClassTeacher">
        select * from classes;
    </select>
    <resultMap id="ClassTeacher" type="com.qcby.entity.Classes">
        <result property="id" column="id"/>
        <result property="className" column="className"/>
        <result property="createTime" column="CreateTime"/>
        <collection property="teachers" ofType="com.qcby.entity.Teacher"
                    column="id" select="getTeacherById"/>
    </resultMap>
    <select id="getTeacherById" resultType="com.qcby.entity.Teacher">
        select teacher.* from teacher left join rel on rel.t_id = teacher.id where c_id = #{id}
    </select>
</mapper>

编写Dao层ClassesDao

package com.qcby.dao;

import com.qcby.entity.Classes;

import java.util.List;

public interface ClassesDao {
    public List<Classes> getClassesTeacher();
}

编写Test测试

package com.qcby;

import com.qcby.dao.ClassesDao;
import com.qcby.entity.Classes;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class ClassesDaoTest {
    private InputStream in = null;
    private SqlSession session = null;
    private ClassesDao mapper = null;

    @Before  //前置通知, 在方法执行之前执行
    public void init() throws IOException {
        //加载主配置文件,目的是为了构建SqlSessionFactory对象
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //通过SqlSessionFactory工厂对象创建SqlSesssion对象
        session = factory.openSession(true);  //关闭
        //通过Session创建UserDao接口代理对象
        mapper = session.getMapper(ClassesDao.class);
    }

    @After  //@After: 后置通知, 在方法执行之后执行 。
    public void destory() throws IOException {
        //释放资源
        session.close();
        in.close();
    }
    @Test
    public void getClassesTeacher(){
        List<Classes> classesTeachers = mapper.getClassesTeacher();
        for (Classes classes:classesTeachers){
            System.out.println(classes.toString());
        }
    }
}

测试结果

 实现延迟加载以及一些对比

lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载

aggressiveLazyLoding:当开启时,任何方式的调用都会加载该对象的所有属性。否则,该属性会按需加载

此时就可以实现按需加载,需要获取的数据是什么,就只会执行相应的sql.此时会通过association和collection中的fetchType属性设置当前的分步查询是否使用懒加载

fetchType=“lazy(延迟加载) | eager(立即加载)”

在SqlMapConfig.xml的settings中配置延迟加载

<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>

设置好延迟加载的配置后,我们在刚刚的Test测试类中测试一下

@Test
    public void getStudent(){
        List<Student> studentTeachers1 = mapper.getStudent();
        for (Student students:studentTeachers1){
            System.out.println(students.getSname());//查询学生的名字(跟老师没关系)
        }

    }

我们可以看到,加上延迟加载后,students.getSname只是查询出了学生的信息,并没有进行第二个sql语句查询老师的信息

再写一个输出进行测试

 @Test
    public void getStudent(){
        List<Student> studentTeachers1 = mapper.getStudent();
        for (Student students:studentTeachers1){
            //System.out.println(students.getSname());//查询学生的名字(跟老师没关系)
            System.out.println(students.getTeacher().getTname());
        }

    }

输出结果为

将没有配置延迟加载的测试结果拿过来进行对比

测试输出1

测试输出2 

经过对比我们发现:

如果配置了延迟加载,查询学生的名字不会对老师进行查询;

如果没有配置延迟加载,查询学生的名字对老师进行查询。

延迟加载和分步查询是绑定在一起的,分步查询可以实现延迟加载,一般情况下我们用延迟加载最多

当我们不想对某一个语句进行延迟加载的时候,我们可以在association标签中写 fetchType

属性设置为 eager

最后再附上我最容易报的一个错误

Result Maps collection does not contain value for....

这个报错去检查<resultMap> 标签里面的字段和 type属性实体类能不能对应的上。。。细心一点吧....

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值