自学Mybatis系列(4)——ResultMap结果映射器


写在前面:十分感谢《深入浅出Mybatis技术原理与实战》这本书,大多数部分是书上的话,希望自己能在后面的文章中多写一些自己的理解。而且最重要的是!每次照书无脑敲的时候,都好羞愧啊(害羞脸)。后面一定注意这些问题。最后要感谢点赞、评论以及指正的朋友们,你们是坠吼的!!!


官方文档有云:

The resultMap element is the most important and powerful element in MyBatis.
resultMap元素是Mybatis中最重要也是最强大的元素。

作用是:定义映射规则、级联的更新、定制类型转换器。
其实我也是刚刚熟悉它,对它的使用并没有达到炉火纯青的地步,毕竟这个元素还是很复杂的。我只是把自己的理解过程记录下来,如果有错误,希望大家指正!


先说说他的结构:

<resultMap>
    <constructor>
        <idArg/>
        <arg/>
    </constructor>
    <id/>
    <result/>
    <association>
    <collection/>
    <discriminator>
        <case/>
    </discriminator>
</resultMap>

眼花缭乱对吧!这里一点一点讲解:
constructor:用于配置构造方法。这里打个比方,当我们的实体类存在没有参数的构造方法时候。就不需要去配置它!比如我们有个Student类参数有id和name。

class Student{
    private int id;
    private String name; 
}

熟悉java基础的同学知道,如果我们不去书写构造方法,那么java会自动帮我们建立一个无参数的构造方法:public Student(){}
但是如果我们写了带有参数的构造方法,这个无参构造方法将不会被自动创建!
所以对于这个构造方法:

public Student(int id,String name){
      this.id = id;
      this.name = name;
}

我们需要配置结果集的constructor:

    <constructor>
        <idArg column="id" javaType="int" />
        <arg column="name" javaType="string"/>
        <arg/>
    </constructor>
  .....
</resultMap>

也就代表着当我们不去写带参构造器的时候就不用去管constructor这个标签。如此即可,是不是理解起来很简单!


id和result
id表示主键的列,允许多个主键,如果是多个的话,就是联合主键。
result配置的是实体类和数据库中列名的映射关系。

我们先不说后面的级联。先研究研究如何储存结果集。
储存结果集有两种方式:1.map 2.pojo(实体类)
但是用map这个方式说实话比较low。阅读性很差,所以pass。
我们使用POJO来存,好处是我们可以利用自动映射,还可以用select中的resultMap属性去配置映射集合。
举个小例子:
假设我们数据库中t_student表有两个字段:student_id和student_name。
我们POJO类中Student类有两个变量:studentId和studentName

我们的select语句如果这么写:(前提是其他文件已经写好)

<select id="getStudents">
    select student_id,student_name from t_student
</select>

这样会发现我们获取到的ID号和姓名是空值,因为字段和变量名不是一一对应的。
我们需要这么写resultMap

<result id="studentResultMap" type="com.cream.pojo.Student">
    <id  property="studentId" column="student_id/>
    <result property="studentName" column="student_name"/>
</result>

此时我们需要在select标签中加上 resultMap="studentResultMap" 即可配置成功。
数据也就可以直接取出来了!这几段我是凭自己记忆写的,之前测试的类被我删掉了,所以大致写个样子,只是为了一看就能马上回忆起来思路!


级联

接下来要说级联了,心里挺没底气的,毕竟是今天早上刚有点开窍,这东西真的是光看是很难理解的,只有自己动手敲一敲再想一想才能真正的悟出来!
Mybatis中的级联有三种:association、collection和discriminator。
discriminator很复杂,先研究完
级联呢,分为三种对应关系:
1.一对一
所谓一对一,打个比方:学生和学生证的关系。一名学生对应一张学生证。这个用association。
2.一对多
所谓一对多,打个比方:公司和员工,一家公司拥有很多员工。这个用collection。
3.多对多
所谓多对多,这个挺烦的:学生和课程。一名学生有很多课程。一门课程,有很多学生!那这个怎么办呢?比如说我们一般再建一张表学生课程表,专门存这个关系,双向使用一对多。达到多对多的关系。当然我们可以向这个表加一些比如说成绩之类的字段精确的存数据。
说了很多,估计看到这里一头雾水。接下来用实例讲解一下。


一对一

书上的例子很好:比如说学生和学生证,他们是一对一的关系。
那么当我们想要通过学生的id号查询到学生的时候,同时取得他的学生证信息,我们应该怎么设计呢?
思路应该是:把学生证(StudentSelfcard)这个类,当做类型放到学生类(Student)中去。
所以建学生类POJO的时候我们需要这么写:
学生类:

public class Student {
    private StudentSelfcard studentSelfcard;  //学生证类在学生类其中
    ...其他参数...
    ......getter and setter方法......  
}

接下来,比如我们要通过学号取查询学生。那么Mapper应该这么写:
StudentSelfcardMapper.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.cream.dao.StudentSelfcardDao">
    <resultMap id="studentSelfacrdMap" type="com.cream.pojo.StudentSelfcard">
        <id property="id" column="id"/>
        <result property="studentId" column="student_id"/>
        <result property="native_" column="native"/>
        <result property="issueDate" column="issue_date"/>
        <result property="endDate" column="end_date"/>
        <result property="note" column="note"/>
    </resultMap>
    <select id="findStudentSelfcardByStudentId" resultMap="studentSelfacrdMap">
        SELECT id,student_id,native,issue_date,end_date,note
        FROM t_student_selfcard WHERE student_id = #{studentId }
    </select>
</mapper>

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.cream.dao.StudentDao">
    <resultMap id="studentMap" type="com.cream.pojo.Student">
        <id property="studentId" column="student_id"/>
        <result property="cnname" column="cnname"/>
        <result property="sex" column="sex"/>
        <result property="note" column="note"/>
        <association property="studentSelfcard" column="student_id"
                     select="com.cream.dao.StudentSelfcardDao.findStudentSelfcardByStudentId"/>
    </resultMap>

    <select id="getStudent" parameterType="int" resultMap="studentMap">
        SELECT student_id,cnname,sex,note FROM  t_student WHERE student_id = #{studentId }
    </select>
</mapper>

关于上面的association讲解一下属性:
property: 映射到结果上的属性,其实就是我们通过关联又获取到了什么类型。
column:我们传送了什么参数过去,这里是student_id那传过去的就是它。
select:代表着由哪条SQL去查询。这里写的是接口以及里面的方法哦,不是xml文件。
在main函数中调用接口和方法即可知道,当我们确定的获取到一个学生信息的时候,同时我们获得了该学生的学生证信息。

一对多

这里想通过多对多去说,所以一对多不想说的太麻烦,先思考,当一对一的时候,是学生中包含着学生证。那么一对多可以用相同的思路来考虑:学生和成绩。一名学生对应着很多成绩,而成绩对应着一名学生。此时需要在学生类的中设置类型为List<成绩>的参数。从而达到,我获取到了一名学生的信息,同时我获取到了一个list,里面放的是这个学生的所有成绩信息。

多对多

其实现实生活中多对多的例子并不多,但我感觉有时候寻思着就把自己带坑里去了,这样来想:学生和课程。一名学生有多门课程,同时一门课程有很多学生去学。这里直接建立联系就很尴尬!
推荐一个方式,建立中间的表。这个表中可以存放学生学号,课程编号,和此学生这门课程的其他信息,比如说老师或者成绩,当然这都是后话了,只需要看这个例子就好。(本人在POJO中把其他无关的地方省略了)
三个POJO:

public class Student {
    private StudentSelfcard studentSelfcard;  //学生证类在学生类其中
    private List<StudentLecture> studentLectureList;
    ...其他参数...
    ......getter and setter方法......  
}
public class Lecture {
    private List<StudentLecture> studentLectureList;
    ...其他参数...
    ......getter and setter方法......  
}
public class StudentLecture {
    private Lecture lecture;
    private Student student;    
      ...其他参数...
    ......getter and setter方法......  
}

三个Mapper.xml,这里就不客气的全粘了:
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.cream.dao.StudentDao">
    <resultMap id="studentMap" type="com.cream.pojo.Student">
        <id property="studentId" column="student_id"/>
        <result property="cnname" column="cnname"/>
        <result property="sex" column="sex"/>
        <result property="note" column="note"/>
        <association property="studentSelfcard" column="student_id"
                     select="com.cream.dao.StudentSelfcardDao.findStudentSelfcardByStudentId"/>
        <collection property="studentLectureList" column="student_id"
                    select="com.cream.dao.StudentLectureDao.findStudentLectureByStuId"/>

    </resultMap>
    <select id="getStudent" parameterType="int" resultMap="studentMap">
        SELECT student_id,cnname,sex,note FROM  t_student WHERE student_id = #{studentId }
    </select>

</mapper>

LectureMapper.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.cream.dao.LectureDao">
    <resultMap id="LectureMap" type="com.cream.pojo.Lecture">
        <id property="courseId" column="course_id"/>
        <result property="lectureName" column="lecture_name"/>
        <result property="note" column="note"/>
        <collection property="studentLectureList" column="lecture_id"
                    select="com.cream.dao.StudentLectureDao.findStudentLectureByLecId"/>
    </resultMap>
    <select id="getLecture" resultMap="LectureMap">
        SELECT lecture_id,lecture_name,note FROM t_lecture WHERE lecture_id = #{lectureId }
    </select>

</mapper>

StudentLectureMapper.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.cream.dao.StudentLectureDao">
    <resultMap id="studentLectureMap" type="com.cream.pojo.StudentLecture">
        <id property="id" column="id"/>
        <result property="studentId" column="student_id"/>
        <result property="lectureId" column="lecture_id"/>
        <result property="grade" column="grade"/>
        <result property="note" column="note"/>
        <association property="lecture" column="lecture_id"
                     select="com.cream.dao.LectureDao.getLecture"/>
        <association property="student" column="student_id"
                     select="com.cream.dao.StudentDao.getStudent"/>

    </resultMap>
    <select id="findStudentLectureByStuId" parameterType="int" resultMap="studentLectureMap">
        SELECT id,student_id,lecture_id,grade,note FROM t_student_lecture WHERE student_id = #{studentId }
    </select>

    <select id="findStudentLectureByLecId" parameterType="int" resultMap="studentLectureMap">
        SELECT id,student_id,lecture_id,grade,note FROM t_student_lecture WHERE lecture_id = #{LectureId }
    </select>

</mapper>

然后通过main来测试
当我们获取到一名学生的时候,同时获得了他的一堆学生课程,通过学生课程们,再一一对应各门课。
当我们获取某一门课的时候,同时获得了这门课的一堆学生课程,通过学生课程们,再一一对应各位学生。
自此结束

总结一下这篇文章:
写的有些凌乱,很多地方自己都快绕蒙了。我的数据库能力真的很生涩。在设计表与表之间的关系思路上也是十分不成熟的。这篇自认为写的也比较一般。希望自己能够在练习中提高。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容