码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2016-04-29 16:08:27      阅读:242      评论:0      收藏:0      [点我收藏+]

标签:

注意讲解都在代码中

准备数据库,测试数据,各位自己添加,因为是多对多,所以使用中间表:
技术分享
用到的实体:
学生类:

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 configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
#log4j.logger.org.mybatis.example.BlogMapper=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.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,student
WHERE 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());
    }
}

懒加载日志显示:
一级查询
技术分享
懒加载查询
技术分享

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

标签:

原文地址:http://blog.csdn.net/do_bset_yourself/article/details/51263101

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!