mybatis实践篇(三)—— ResultMap映射详细介绍

ResultMap

ResultMap 的设计思想是,对于简单的语句不需要配置结果映射,而对于复杂一点的语句只需要描述它们的关系。下面来看一下ResultMap下的部分标签和属性:


<!-- 非常复杂的结果映射 -->
<resultMap id="detailedBlogResultMap" type="Blog">
        <!-- 实例化类时,注入结果到构造方法中 -->
      <constructor>
            <idArg column="blog_id" javaType="int"/>
      </constructor>
              <!-- title属性,对应库中的blog_title列-->
      <result property="title" column="blog_title"/>
             <!-- 对象类型数据 Author author -->
      <association property="author" javaType="Author">
            <id property="id" column="author_id"/>
            <result property="username" column="author_username"/>
            <result property="password" column="author_password"/> 
      </association>
        <!-- 集合类型数据 List<Post> posts, Post中还包含其他复杂类型-->
      <collection property="posts" ofType="Post">
            <id property="id" column="post_id"/>
            <result property="subject" column="post_subject"/>
                <!-- 调用上面的association -->
            <association property="author" javaType="Author"/>
            <collection property="comments" ofType="Comment">
                  <id property="id" column="comment_id"/>
            </collection>
            <collection property="tags" ofType="Tag" >
                   <id property="id" column="tag_id"/>
            </collection>
                <!-- 使用结果值来决定使用哪个 resultMap -->
            <discriminator javaType="int" column="draft">
                  <case value="1" resultType="DraftPost"/>
            </discriminator>
      </collection>
</resultMap>


看着是不是有点晕,ResultMap是这么复杂的吗?其实捋顺了ResultMap中的结构,也就不觉得它有多么复杂了,而且上面提到的所有子标签也并不是都经常遇到。只有result、collection和association使用的频率会高一些。

ResultMap标签中有三个属性:id、type、autoMapping

  • id:resultMap的唯一标识
  • type:类的完全限定名或类的别名
  • autoMapping(慎用):设置这个属性,MyBatis将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset)。

下面我们就逐个的来讲解一下ResultMap中的这些子标签以及它们的强大功能。

id、result

id标签用于标识数据库表中主键列和类中属性的对应关系:

 <id property="属性名" column="表中的主键列"/>

result标签配置对象中的属性和数据库表中列的对应关系

<result property="pojo中的属性名" column="对应数据库表中的column"/>

Collection:

collection在JDK中是集合接口,所有集合类型都需要实现它,所以这里也不难理解在mybatis中它的作用是用来配置对象中的集合类型数据。但是collection的使用远远不止我们上面例子中使用的那么简单。下面就来看看collection能做什么:

首先我们创建三张表:grade、student、grade_student,对应两个类Grade和Student

 

@Data
public class Grade {

    private int id;

    private String name;

    private List<Student> studentList;
}

@Data
public class Student {

    private String id;

    private String name;

    private int age;
}

1、映射简单对象

    <resultMap id="grade" type="cn.zsm.mybatis.student.Grade">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
    </resultMap>

    <select id="selectGrades" resultMap="grade" >
        select * from grade
    </select>

这种映射一般都会省略,因为即使列名与pojo中的属性名不同,也可以直接为列取别名与pojo中的属性进行映射

2、映射对象中的集合类型,结果嵌套

这次我们将使用一个查询获取班级和学生的信息。

    <resultMap id="grade" type="cn.zsm.mybatis.student.Grade">
        <id property="id" column="gid"/>
        <result property="name" column="gname"/>
        <collection property="studentList" ofType="cn.zsm.mybatis.student.Student">
            <id property="id" column="id"/>
            <result property="name" column="name"/>
            <result property="age" column="age"/>
        </collection>
    </resultMap>

    <select id="selectGrades" resultMap="grade" >
        select g.id gid,g.name gname,s.id, s.name, s.age from grade g
        inner join grade_student gs on g.id = gs.class_id
        inner join student s on s.id = gs.student_id
    </select>
List<Grade> selectGrades();

查询结果为:

[Grade(id=1, name=一班, 
        studentList=[Student(id=1, name=stu1, age=10), 
                    Student(id=2, name=stu2, age=10), 
                    Student(id=3, name=stu3, age=11)]), 
Grade(id=2, name=二班, 
        studentList=[Student(id=4, name=stu4, age=10), 
                    Student(id=1, name=stu1, age=10)])
]

3、配置对象中的集合类型,关联的查询语句嵌套

    <resultMap id="grade" type="cn.zsm.mybatis.student.Grade">
        <id property="id" column="gid"/>
        <result property="name" column="gname"/>
        <collection property="studentList" ofType="cn.zsm.mybatis.student.Student" column="gid" select="getStudents"/>
    </resultMap> 

    <select id="selectGrades" resultMap="grade" >
        select g.id gid,g.name gname  from grade g
    </select>

    <select id="getStudents" resultType="cn.zsm.mybatis.student.Student">
        select s.* from student s
        inner join grade_student gs on s.id = gs.student_id
        where gs.class_id = #{id}
    </select>
List<Grade> selectGrades();

查询结果与上面的结果相同。

注意,这里在配置Grade的resultMap时,配置studentList属性时,与上面的配置大不相同。这里使用了collection标签的column、select属性,select用于指定要嵌套的查询方法,而column用于指定传入嵌套方法中的参数和参数名——如果嵌套方法的查询参数是简单类型,则如上面的例子中使用,多个参数使用【逗号】分隔;如果嵌套方法的查询参数是对象类型,则column取值格式为:{"paramName":"columnName","paramName":"columnName",......}。(对此可参考:Mybatis注解@ResultMap

association :

association用于配置对象结果映射,比如上面的例子中,每个学生都有一个班级,我们可以在Student类中添加一个Grade类型的变量 Grade grade,如下所示:

@Data
public class Grade {

    private int id;

    private String name; 
}

@Data
public class Student {

    private String id;

    private String name;

    private int age;

    private Grade grade;
}

这样我们在查询Student信息时,也可以顺带查询出该学生所属的班级信息。(注意,上面的数据中有一个学生属于两个班级,需要修改该数据)。

下面我们来实现该查询。

    <resultMap id="student" type="cn.zsm.mybatis.student.Student">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <association property="grade" javaType="cn.zsm.mybatis.student.Grade">
            <id property="id" column="gid"/>
            <result property="name" column="gname"/>
        </association>
    </resultMap>

    <select id="selectStudents" resultMap="student">
        select s.id, s.name, s.age, g.id gid, g.name gname from student s
        inner join grade_student gs on s.id = gs.student_id
        inner join grade g on g.id = gs.class_id
    </select>
 List<Student> selectStudents();

查询结果为:

association与collection的使用基本相同,只不过一个是配置对象集合类型,一个是封装单个对象类型属性。association中也有select、column等属性,用法与collection相同,这里就不再多说了。

constructor:

通过修改对象属性的方式,可以满足大多数的数据传输对象(Data Transfer Object, DTO)以及绝大部分领域模型的要求。但有些情况下你想使用不可变类。 一般来说,很少改变或基本不变的包含引用或数据的表,很适合使用不可变类。 构造方法注入允许你在初始化时为类设置属性的值,而不用暴露出公有方法。MyBatis 也支持私有属性和私有 JavaBean 属性来完成注入,但有一些人更青睐于通过构造方法进行注入。 constructor 元素就是为此而生的

看看下面这个构造方法:

public class User { 
   ........
   public User(Integer id, String username, int age) {
     //...
  } 
}

为了将结果注入构造方法,MyBatis 需要通过某种方式定位相应的构造方法。 在下面的例子中,MyBatis 搜索一个声明了三个形参的的构造方法,参数类型以 java.lang.Integer, java.lang.String 和 int 的顺序给出。

<constructor>
   <idArg column="id" javaType="int"/>
   <arg column="username" javaType="String"/>
   <arg column="age" javaType="_int"/>
</constructor>

constructor很少使用,用兴趣的可以去官网详细查看:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#Result_Maps

发布了74 篇原创文章 · 获赞 19 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/zhoushimiao1990/article/details/100085411