mybatis懒加载特性详解,以及多对多映射详解

来源:互联网 发布:淘宝网披肩女装 编辑:程序博客网 时间:2024/05/16 05:06

注意讲解都在代码中

准备数据库,测试数据,各位自己添加,因为是多对多,所以使用中间表:
这里写图片描述
用到的实体:
学生类:

public class Student {    private Integer sid;    private String name;    private Integer age;    //一个学生有多个老师,一个老师有多个学生    private List<Teacher> teachers=new ArrayList<Teacher>();        setter..        getter....        toString}

老师类:

public class Teacher {    private Integer tid;    private String tname;    private String subject;    //一个学生有多个老师,一个老师有多个学生    private List<Student> students=new ArrayList<Student>();        setter..        getter....        toString}

sql工具类:

package com.leige.test;import java.io.IOException;import java.io.InputStream;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;/** * @author sqlsession工具类 * */public class SqlUtils {    static SqlSessionFactory factory;    //静态加载session工厂    static{        InputStream inputStream;        try {            inputStream = Resources.getResourceAsStream("com/leige/config/configuration.xml");            //1:实例化sqlsessionfactory工厂            factory= new SqlSessionFactoryBuilder().build(inputStream);        } catch (IOException e) {        }    }    public static SqlSession getSession() {        try{        //开启session        return factory.openSession();        }catch(Exception e){            throw new RuntimeException(e);        }    }    /**     * @param session     * @param mapper     * @return     * 保证会话session一致,所以当做参数传过来     */    public static Object getmaMapper(SqlSession session,Class mapper){        //注册映射接口        factory.getConfiguration().addMapper(mapper);        //返回操作实例        return session.getMapper(mapper);    }}

全局配置不在全部贴出来了,需要说明的是,使用懒加载需要开启懒加载开关,还需要日志检测懒加载,还需要动态代理的cglib包,以及依赖包asm,和日志包

开启懒加载以及扫描包,自动分配名空间,在全局配置中需加入的配置

<!--  首先在全局配置中配置支持懒加载 -->    <settings>          <setting name="lazyLoadingEnabled" value="true"/>          <setting name="aggressiveLazyLoading" value="false"/>            <setting name="logImpl" value="LOG4J"/>    </settings>      <typeAliases>     <!--    声明po类别名 -->        <typeAlias alias="Student" type="com.leige.domain.Student"/><!--         声明组合查询类 -->       <!--  <typeAlias alias="StudentQueryVo" type="com.leige.domain.StudentQueryVo" />        <typeAlias alias="Teacher" type="com.leige.domain.Teacher"/> --><!--         配置多个扫描,默认类的简单名称,不区分大小写 -->        <package name="com.leige.domain"/>    </typeAliases>

日志配置:

# Global logging configurationlog4j.rootLogger=DEBUG, stdout# MyBatis logging configuration...#log4j.logger.org.mybatis.example.BlogMapper=DEBUG# Console output...log4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

Student接口映射:

<?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"><!--  命名空间就是实现sql的隔离,把对于一个对象的操作sql语句放在一个命名空间中 这里的调用查询就是Student.selectStudentById --><mapper namespace="Student"><!-- 根据学生id查询学生信息及所有老师信息, 当然大家也可以不使用嵌套查询,也可以直接使用三表查询,效率较低,我是直接复制过来的注意sql小问题哦      SELECT student.*,teacher.* FROM  student,t_s,teacher       WHERE student.`sid`=t_s.`sid` AND teacher.`tid`=t_s.`tid` AND t_s.sid=1 --><!--       定义结果map -->      <resultMap type="Student" id="Student_Teacher">            <id column="sid" property="sid"/>          <result column="name" property="name"/>          <result column="age" property="age"/>      <collection property="teachers" ofType="Teacher">         <!--  property表示集合属性,ofType表示集合类型 -->             <id column="tid" property="tid"/>          <result column="tname" property="tname"/>          <result column="subject" property="subject"/>      </collection>      <!--       association的使用和collection类似,多用于一对一映射或者一对多一方的resultMap的输出映射              <association property=""></association> -->          </resultMap>          <!-- 懒加载 ,由于是多对多,所以需要加查询中间表,所以,不能直接使用单表id查询--><select id="selectStudentLazy" parameterType="int" resultType="Student" >        <![CDATA[            SELECT student.* FROM student,t_s           WHERE            t_s.sid=student.sid AND t_s.tid=#{value}          ]]></select><!-- 多对多级联查询,其实个人感觉,mybatis的映射关系主要体现在数据库设计和sql语法上面如果数据库基础知识过硬,没必要花费时间去学习 --><select id="select_student_teacher" parameterType="int" resultMap="Student_Teacher">               <![CDATA[         SELECT tt.*,teacher.`tname`,teacher.`subject` FROM teacher,    (SELECT student.*,t_s.`tid` FROM student,t_s WHERE student.`sid`=t_s.`sid`) tt     WHERE     tt.tid=teacher.`tid`  AND sid=#{value} ]]></select></mapper>

Teacher接口映射,大家可以对比下,使用懒加载和未使用懒加载时resultMap的区别,仔细思考就会发现其实很简单

<?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="Teacher"><!--     未使用懒加载时的resultMap -->      <resultMap type="Teacher" id="Teacher_Student">          <id column="tid" property="tid"/>          <result column="tname" property="tname"/>          <result column="subject" property="subject"/>      <collection property="students" ofType="Student">         <!--  property表示集合属性,ofType表示集合类型 -->          <id column="sid" property="sid"/>          <result column="name" property="name"/>          <result column="age" property="age"/>      </collection>      <!--       association的使用和collection类似,多用于一对一映射或者一对多一方的resultMap的输出映射              <association property=""></association> -->          </resultMap>        <select id="selectTeahcerById" parameterType="int" resultType="Teacher" >          <![CDATA[          select * from teacher where id=#{value}          ]]>      </select>      <!-- 未使用懒加载时,联合查询关键是sql语句的调优,      这里简单介绍一下mybatis的对象映射关系,其实学习mybatis的对象映射,个人大家不必花费时间去学习,      因为都是相通的,主要是数据库表的设计,具体的查询映射,主要体现在sql语法上,数据库知识过硬,没有学习的必要,      这里由于本人数据库知识有限,抱歉没有优化,能查出来,我就很高兴了      当然大家不使用嵌套查询,也可以直接使用三表查询,效率较低      SELECT student.*,teacher.* FROM  student,t_s,teacher       WHERE student.`sid`=t_s.`sid` AND teacher.`tid`=t_s.`tid` AND t_s.sid=1       -->      <select id="selectNoLazy" parameterType="int" resultMap="Teacher_Student">            <![CDATA[        SELECT tt.*,student.name,student.age FROM (SELECT teacher.*,t_s.sid FROM teacher,t_s WHERE teacher.tid=t_s.tid) tt,studentWHERE tt.sid=student.sid AND tid=#{value}          ]]>      </select>      <!--       mybatis使用懒加载需使用resultMap,在resultMap中有collections和associatation标签都支持懒加载resultType不可以将属性列和集合映射,所以需要使用resultMap这里最重要的就是懒加载的实现,mybatis对于懒加载的实现就是延迟使用子查询的发出,这与hibernate的机制是一样的所以子查询是懒加载的灵魂,下面是定义懒加载的resultMap,懒加载和非懒加载的resultMap的区别就是关联映射使用的是子查询,子查询调用的时外部Student中的懒加载子查询,需要加上命名空间 --> <resultMap type="Teacher" id="Teacher_Student_lazy">        <id column="tid" property="tid"/>          <result column="tname" property="tname"/>          <result column="subject" property="subject"/> <!--      select:基于column列发出的子查询语句,即SELECT student.* FROM student where sid=?; column:就是与select相关联的另一个表中的列 例如这里完整的查询是:   父查询   SELECT * FROM teacher WHERE tid=?   子查询根据父查询的tid再去查询学生表,因为是多对多,所以需要查询中间表   SELECT student.* FROM student,t_s           WHERE            t_s.sid=student.sid AND t_s.tid=#{value}-->      <collection property="students" ofType="Student" select="Student.selectStudentLazy" column="tid" >       <!-- 用于懒加载关联的查询 -->      </collection> </resultMap>    <select id="selectTeacherLazy" parameterType="int" resultMap="Teacher_Student_lazy"><!--      由于这是多对多映射,所以查询多关联关系,需要借助中间表,所以使用resultMap -->       <![CDATA[      select * from teacher where tid=#{value}       ]]> </select>  </mapper>

多对多映射详解
这里简单介绍一下mybatis的对象映射关系,其实学习mybatis的对象映射,个人大家不必花费时间去学习,
因为都是相通的,主要是数据库表的设计,具体的查询映射,主要体现在sql语法上,数据库知识过硬,没有学习的必要,多对多映射的解释请查看测试代码具体感受下:
测试代码

package com.leige.test;import org.apache.ibatis.session.SqlSession;import org.junit.Test;import com.leige.domain.Student;import com.leige.domain.Teacher;public class App2 {    @Test    public void testSelectLazy(){        //获取session        SqlSession session=SqlUtils.getSession();        //查询        Teacher teacher=session.selectOne("Teacher.selectTeacherLazy", 1);        //打印        //测试懒加载时可以在此处打断点,就会发现只有在使用子集合时才会加载        System.out.println(teacher);        //真正加载的位置        System.out.println(teacher.getStudents());    }    /**     * 测试立即加载,实现多对多,获取实现     */    @Test    public void testSelectNoLazy(){        //获取session                SqlSession session=SqlUtils.getSession();                /*//根据id查询老师信息,以及老师教的所有学生的信息,                当然这种例子是不合理的,现实中要么是学生单项关联老师,                或者以班级为单位,老师学生都关联班级,但是这里只是演示多对多以及懒加载,至于对象和具体问题的处理还需要大家自己设计*/                Teacher teacher=session.selectOne("Teacher.selectNoLazy", 1);                //打印                System.out.println(teacher);                System.out.println(teacher.getStudents());                System.out.println("---------------------------我是分割线-------------------");                //根据学生id查询学生信息,以及学生的所有老师信息                Student student=session.selectOne("Student.select_student_teacher",1);                //输出                System.out.println(student);                System.out.println(student.getTeachers());    }}

懒加载日志显示:
一级查询
这里写图片描述
懒加载查询
这里写图片描述

0 0
原创粉丝点击