java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Mybatis关联映射

Mybatis关联映射的实现

作者:期待のcode

本文介绍了MyBatis关联映射的实现方式,直接查询和分步查询,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

数据部分:

student表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `Sname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `sex` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `t_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (1, '张三', '男', 18, 1);
INSERT INTO `student` VALUES (2, '李四', '女', 18, 1);
INSERT INTO `student` VALUES (3, '王五', '男', 18, 1);
INSERT INTO `student` VALUES (4, '小白', '女', 18, 1);
INSERT INTO `student` VALUES (5, '小黑', '男', 18, 1);
INSERT INTO `student` VALUES (6, '小红', '女', 20, 2);
INSERT INTO `student` VALUES (7, '小李', '男', 20, 2);
INSERT INTO `student` VALUES (8, '小张', '女', 20, 2);
INSERT INTO `student` VALUES (9, '小赵', '男', 20, 2);
INSERT INTO `student` VALUES (10, '小王', '女', 20, 2);

SET FOREIGN_KEY_CHECKS = 1;

teacher表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for teacher
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `Tname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of teacher
-- ----------------------------
INSERT INTO `teacher` VALUES (1, '张老师');
INSERT INTO `teacher` VALUES (2, '李老师');

SET FOREIGN_KEY_CHECKS = 1;

查询老师的学生sql信息语句与查询结果如下:

查询学生的老师信息sql语句与查询结果如下:

直接查询

查询出来的数据用TeacherStudents实体类进行封装

TeacherStudents.java

package com.qcby.entity;

public class TeacherStudents {
    private Integer id;
    private String Tname;
    private String Sname;
    private String sex;

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

    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 String getSname() {return Sname;}

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

    public String getSex() {return sex;}

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

TeacherStudentMapper.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.TeacherStudentsDao">
    <select id="findTeacherStudents" resultType="com.qcby.entity.TeacherStudents">
        select teacher.*,student.Sname,student.sex from teacher left join student on student.t_id = teacher.id
    </select>
</mapper>

SqlMapConfig.xml

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

TeacherStudentsDao.java

package com.qcby.dao;
import com.qcby.entity.TeacherStudents;
import java.util.List;

public interface TeacherStudentsDao {
    List<TeacherStudents> findTeacherStudents();
}

TeacherStudentsTest.java

import com.qcby.dao.TeacherStudentsDao;
import com.qcby.entity.TeacherStudents;
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 TeacherStudentsTest {
    private InputStream in = null;
    private SqlSession session = null;
    private TeacherStudentsDao teacherStudentsDao = 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();
        //通过Session创建UserDao接口代理对象
        teacherStudentsDao = session.getMapper(TeacherStudentsDao.class);
    }

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


    @Test
    public void findAll(){
        List<TeacherStudents> list = teacherStudentsDao.findTeacherStudents();
        System.out.println(list.toString());
    }
}

直接查询的查询结果:

关联映射

student 表和 teacher 表存在着一对多与多对一的关系,我们介绍 MyBatis 中处理关联关系的两种关联映射查询方式,分别是直接查询与分布查询。

直接查询通过 SQL 的JOIN(如LEFT JOIN、INNER JOIN)关联多个表,进行联合查询获取主表和关联表的所有所需字段,然后在<resultMap>中通过<association>一对一或<collection>一对多标签,定义主表与关联表字段到对应实体属性的映射规则,MyBatis 会自动将查询结果分别封装为主实体和关联实体,并将关联实体注入主实体的关联属性中。

分步查询是分阶段完成查询,先执行主查询获取主实体数据及关联字段(select * from student),再由 MyBatis 自动根据关联字段调用对应 Mapper 方法,执行关联查询获取关联实体数据(select * from teacher where id = #{t_id}),最终将关联实体自动封装到主实体的关联属性中。可结合延迟加载,仅在使用关联数据时触发关联查询。

下面我们来看详细代码:

SqlMapConfig.xml

  <mappers>
        <mapper resource="mapper/StudentMapper.xml"></mapper>
        <mapper resource="mapper/TeacherMapper.xml"></mapper>
    </mappers>

Student.java

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;

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

    public Teacher getTeacher() {return teacher;}

    public void setTeacher(Teacher teacher) {this.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;}
}

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.qcby.dao.StudentDao">
    
    <select id="findStudentTeacher" resultMap="studentTeacher">
        select student.*,teacher.Tname from student left join teacher on student.t_id = teacher.id
    </select>
    <resultMap id="studentTeacher" type="com.qcby.entity.Student">
        <id 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 property="teacher" javaType="com.qcby.entity.Teacher">
            <result property="Tname" column="Tname"/>
        </association>
    </resultMap>

    <select id="findStudentTeacher1" resultMap="studentTeacher1">
        select * from student
    </select>
    <resultMap id="studentTeacher1" type="com.qcby.entity.Student">
        <id 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 property="teacher" javaType="com.qcby.entity.Teacher"
                     select="com.qcby.dao.TeacherDao.findTeacherByT_id" column="t_id">
        </association>
    </resultMap>
    
    <select id="findStudentByT_id" resultType="com.qcby.entity.Student">
        select * from student where t_id = #{id}
    </select>
    
</mapper>

<select> 标签用于主查询,resultMap 属性用于指定映射规则
<resultMap> 标签用于结果映射规则,其中 id 属性值要与 select 标签中的 resultMap 属性值相同,是映射规则的唯一标识,type 指定映射的目标实体类,result 映射普通字段,property=实体类中的属性名,column=数据库当中的字段,而 <association> 标签用于处理对象的关联信息,其中 property=关联对象的属性名、javaType=关联对象的类型、select=对应的查询方法、column=传递给关联查询的参数

StudenDao.java

package com.qcby.dao;
import com.qcby.entity.Student;
import java.util.List;

public interface StudentDao {
    List<Student> findStudentTeacher();

    List<Student> findStudentTeacher1();

    Student findStudentByT_id(Integer t_id);
}

StudentTest.java

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 StudentTest {
    private InputStream in = null;
    private SqlSession session = null;
    private StudentDao studentDao = 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();
        //通过Session创建UserDao接口代理对象
        studentDao = session.getMapper(StudentDao.class);
    }

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

    @Test
    public void findStudentTeacher(){
        List<Student> students = studentDao.findStudentTeacher();
        System.out.println(students.toString());
    }

    @Test
    public void findStudentTeacher1(){
        List<Student> students = studentDao.findStudentTeacher();
        System.out.println(students.toString());
    }
}

findStudentTeacher() 直接查询结果如下:

findStudentTeacher1() 分步查询结果如下:

Teacher.java

package com.qcby.entity;
import java.util.List;

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

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

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

    public void setStudents(List<Student> students) {this.students = 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;}
}

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

    <select id="getStudents" resultMap="teacherStudents">
        select teacher.*,student.Sname,student.sex from teacher left join student on student.t_id = teacher.id
    </select>
    <resultMap id="teacherStudents" type="com.qcby.entity.Teacher">
        <id property="id" column="id"/>
        <result property="Tname" column="Tname"/>
        <collection property="students" ofType="com.qcby.entity.Student">
            <result property="Sname" column="Sname"/>
            <result property="sex" column="sex"/>
        </collection>
    </resultMap>

    <select id="findTeacherByT_id" resultType="com.qcby.entity.Teacher">
        select * from teacher where id = #{t_id}
    </select>

    <select id="getStudents1" resultMap="teacherStudents1">
        select * from teacher
    </select>
    <resultMap id="teacherStudents1" type="com.qcby.entity.Teacher">
        <id property="id" column="id"/>
        <result property="Tname" column="Tname"/>
        <collection property="students" ofType="com.qcby.entity.Student"
                    select="com.qcby.dao.StudentDao.findStudentByT_id" column="id" fetchType="lazy"/>
    </resultMap>
    
</mapper>

在 Teacher.java 中 student 属性的类型是 List 集合,collection 标签用于处理集合映射到 Student.java 中,oftype=集合泛型的类型

TeacherDao.java

package com.qcby.dao;
import com.qcby.entity.Teacher;
import java.util.List;

public interface TeacherDao {
    List<Teacher> getStudents();

    Teacher findTeacherByT_id(Integer t_id);

    List<Teacher> getStudents1();
}

TeacherTest.java

import com.qcby.dao.TeacherDao;
import com.qcby.entity.Teacher;
import com.qcby.entity.TeacherStudents;
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 TeacherTest {
    private InputStream in = null;
    private SqlSession session = null;
    private TeacherDao teacherDao = 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();
        //通过Session创建UserDao接口代理对象
        teacherDao = session.getMapper(TeacherDao.class);
    }

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

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

    @Test
    public void getStudents1(){
        List<Teacher> teachers = teacherDao.getStudents1();
        for (Teacher teacher:teachers){
            System.out.println(teacher);
            System.out.println(teacher.getTname());
            System.out.println(teacher.getStudents());
        }
    }
}

getStudents() 直接查询结果如下:

getStudents1() 分步查询结果如下:

延迟加载

MyBatis 的延迟加载(Lazy Loading)是一种优化数据库查询性能的机制,它允许在需要时才加载关联对象的数据,而不是在加载主对象时就立即加载所有关联数据。这种 “按需加载” 的方式可以减少不必要的数据库查询,提升系统性能。

延迟加载实现效果如图:

只执行了一个sql’语句,当查询该对象时,只加载该对象本身的属性,对于其关联的对象暂不加载,直到程序真正需要访问这些关联对象时,才会发起对应的数据库查询

如何配置延迟加载

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

lazyLoadingEnabled 是延迟加载的全局开关,aggressiveLazyLoading 对 lazyLoadingEnabled 的补充配置,当开启延迟加载,aggressiveLazyLoading 再设置为 true 时,任何方式调用都会加载该对象的所有属性,设置为 false 则该属性将按需加载,若 lazyLoadingEnabled=false 关闭延迟加载时,此配置无效,所有关联对象都会立即加载。

	<collection property="students" ofType="com.qcby.entity.Student"
                    select="com.qcby.dao.StudentDao.findStudentByT_id" column="id" fetchType="lazy"/>

fetchType有两个值,一个是"lazy"为懒加载,一个是"eager"为立即加载

到此这篇关于Mybatis关联映射的实现的文章就介绍到这了,更多相关Mybatis关联映射内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文