标签:
注意讲解都在代码中
准备数据库,测试数据,各位自己添加,因为是多对多,所以使用中间表:
用到的实体:
学生类:
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());
}
}
懒加载日志显示:
一级查询
懒加载查询
标签:
原文地址:http://blog.csdn.net/do_bset_yourself/article/details/51263101