MyBatis学习(一)之一对一关联映射查询

来源:互联网 发布:苹果设计软件sketch 编辑:程序博客网 时间:2024/05/26 15:54
最近正在学习MyBatis,发现这个MyBatis在处理对象间的关联关系的时候还是比较绕的,很难让人理解,所以,自己搜集了各种资料,并且亲身逐一进行测试,然后在这里写下这篇文章,就当是来理理自己的思路了。

其实不管是一对一映射还是一对多映射关系,在处理关联对象的时候都有两种方式,即使用嵌套的ResultMap和嵌套Select两种方式,本篇将以单、双向一对一为例来相信介绍关联映射的配置方式,一对多将在后续文章中介绍。环境已准备好:

使用班级类Classes{id,name,teacherId}和老师类Teacher{id,name},一个老师对应着一个班级,Classes类中的teacherId引用Teacher类中的id,此外还有其对应的接口,其中各包含一个根据ID查询对象的方法下面来完成根据Classes的Id来查询Classes并查询出 其关联的Teacher信息

一、单向的一对一

(1)使用嵌套Select的方式

所谓嵌套Select的方式,就是通过执行另外一个SQL映射语句来返回预期的复杂类型,其实说白了就是分别查询两张表的数据

1.实体类已创建,在Classes类中创建Teacher类的字段,表示单向一对一

2.创建ClassesMapper.xml文件,通过association元素来映射对象,编写如下配置:

[html] view plain copy
  1. <mapper namespace="com.wzj.dao.IClassesDao">  
  2.     <resultMap type="com.wzj.entity.Classes" id="classesMap">  
  3.         <id property="id" column="c_id" />  
  4.         <result property="name" column="c_name" />  
  5.         <!--省略普通属性  -->  
  6.         <!--映射teacher对象,通过嵌套select语句方式,也就是再通过一条sql语句查询   
  7.             property:java中字段名称,此处为teacher   
  8.             select:使用另一个查询封装的结果   
  9.             column:外键列,很重要,根据此列去查询对应的teacher -->  
  10.         <association property="teacher"  select="com.wzj.dao.ITeacherDao.selectTeacherById" column="teacher_id" />  
  11.     </resultMap>  
  12.   
  13.     <!-- 根据接口中定义的方法来编写sql语句 -->  
  14.     <select id="selectClassesById" parameterType="int"resultMap="classesMap">  
  15.         select * from classes where c_id=#{id}  
  16.     </select>  
  17. </mapper>  

selectClassesById中的sql语句仅需要查询出Classes表的数据即可,然后映射的时候会再根据association中的select元素查询teacher表的数据,Teacher和CLasses是有关联的,查询Teacher必然要传递给其Id,那么这里的column就起到了作用了!

3.创建TeacherMapper.xml文件,这个就比较好配置了,不过也要注意sql语句:

[html] view plain copy
  1. <mapper namespace="com.wzj.dao.ITeacherDao">  
  2.     <resultMap type="com.wzj.entity.Teacher" id="teacherMap">  
  3.         <id property="id" column="t_id" />  
  4.         <result property="name" column="t_name" />  
  5.     </resultMap>  
  6.     <!-- 根据参数来查询Teacher -->  
  7.     <select id="selectTeacherById" resultMap="teacherMap">  
  8.         select * from teacher where t_id=#{id}  
  9.     </select>  
  10. </mapper>  
4.创建测试类,运行正常输出了结果:
[java] view plain copy
  1. public static void main(String[] args) {  
  2.         SqlSession session=MybatisUtil.currentSqlSession();  
  3.           
  4.         IClassesDao dao=session.getMapper(IClassesDao.class);  
  5.         Classes c=dao.selectClassesById(1);  
  6.         Teacher t=c.getTeacher();  
  7.         System.out.println(c.getName()+"\t"+t.getName());  
  8.           
  9.         session.commit();  
  10.         MybatisUtil.closeSqlSession();  
  11.     }  
(2)使用嵌套的resultMap方式

在一条sql语句中使用连接查询出两张表的数据,然后在resultMap中再嵌套映射结果

1.对以上的ClassesMapper.xml进行修改:

[html] view plain copy
  1. <mapper namespace="com.wzj.dao.IClassesDao">  
  2.     <resultMap type="com.wzj.entity.Classes" id="classesMap">  
  3.         <id property="id" column="c_id" />  
  4.         <result property="name" column="c_name" />  
  5.         <!-- 同样使用association元素,标签不再是闭合,里面嵌套映射teacher对象的子标签   
  6.             property:对象名称   
  7.             javaType:声明要映射的类型完整名称或者别名  
  8.              -->  
  9.         <association property="teacher" javaType="com.wzj.entity.Teacher">  
  10.             <id property="id" column="t_id" />  
  11.             <result property="name" column="t_name" />  
  12.         </association>  
  13.     </resultMap>  
  14.     <!-- 使用连接查询一并查出 -->  
  15.     <select id="selectClassesById" resultMap="classesMap">  
  16.         select * from classes c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id}  
  17.     </select>  
  18. </mapper>  

2.进行测试,正常输出结果:
[java] view plain copy
  1. IClassesDao dao=session.getMapper(IClassesDao.class);  
  2.         Classes c=dao.selectClassesById(1);  
  3.         Teacher t=c.getTeacher();  
  4.         System.out.println(c.getName()+"\t"+t.getName());  

以上就是单向的一对一查询

二、双向一对一

其实明白了上面单向的一对一之后,双向的就简单了,一样的一个过程,本例以Classes中使用嵌套resultMap方式、Teacher中使用嵌套select来进行简单的阐述。

1.在Teacher类中添加Classes的字段classses

2.修改ClassesMapper.xml:

[html] view plain copy
  1. <mapper namespace="com.wzj.dao.IClassesDao">  
  2.     <resultMap type="com.wzj.entity.Classes" id="classesMap">  
  3.         <id property="id" column="c_id" />  
  4.         <result property="name" column="c_name" />  
  5.         <!-- 映射结果中的Teacher对象  
  6.             property:字段名称  
  7.             javaType:要映射的类型的完整名称或者别名  
  8.              -->  
  9.         <association property="teacher" javaType="com.wzj.entity.Teacher">  
  10.             <id property="id" column="t_id" />  
  11.             <result property="name" column="t_name" />  
  12.             <!-- 这里要再嵌套映射Teacher类中的Classes对象 -->  
  13.             <association property="classes" column="teacher_id"  select="com.wzj.dao.IClassesDao.selectClassesById" />  
  14.         </association>  
  15.     </resultMap>  
  16.     <select id="selectClassesById" resultMap="classesMap">  
  17.         select * from classes c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id}  
  18.     </select>  
  19. </mapper>  
3.TeacherMapper.xml中:
[html] view plain copy
  1. <mapper namespace="com.wzj.dao.ITeacherDao">  
  2.     <resultMap type="com.wzj.entity.Teacher" id="teacherMap">  
  3.         <id property="id" column="t_id" />  
  4.         <result property="name" column="t_name" />  
  5.         <association property="classes" column="t_id"  
  6.             select="com.wzj.dao.IClassesDao.selectClassesById" />  
  7.     </resultMap>  
  8.     <select id="selectTeacherById" resultMap="teacherMap">  
  9.         select * from teacher where t_id=#{id}  
  10.     </select>  
  11. </mapper>  

注意:在这里的话,association元素中的column要写t_id了,因为映射结果中没有teacher_id一列

4.运行测试类,成功输出结果.

以上就是单向和双向的一对一关联关系,总的来说,使用嵌套的select方式,会引起N+1查询的问题,因为它会根据Classes中的每一个记录再访问数据,这样频繁的访问数据势必会导致系统性能的下降,关于N+1查询问题,能力有限,就不阐述了,感兴趣的童鞋可以百度一下。