Mybatis-<resultMap>标签详解

原创
2018/01/27 15:40
阅读数 5.9W

<resultMap>是Maybatis的结果集封装,搭配<select><association>等标签的resultMap属性使用

属性:

    id:该封装规则的唯一标识

    type:封装出来的类型,可以是jdk自带的,比如Map,应该可以是自定义的,比如Employee

    autoMapping:自动封装,如果数据库字段和javaBean的字段名一样,可以使用这种方式,但是不建议采取,还是老老实实写比较稳妥,如果非要使用此功能,那就在全局配置中加上mapUnderscoreToCamelCase=TRUE,它会使经典数据库字段命名规则翻译成javaBean的经典命名规则,如:a_column翻译成aColumn

    extends:继承其他封装规则,和Java中的继承一样,也特别适合这样的场景

子标签:

    <id>

            用来标识出对象的唯一性,比如用表的主键,如:

            <id column="employee_id" property="empId"/>

            column指定数据库字段名或者其别名

            property指定javaBean的属性名

            还有jdbcType,javaType,typeHandler,分别数据库类型,属性的java类型,数据库与Java类型匹配处理器

            默认的类型匹配处理器有:

            

            以上罗列的资料不全,可以参考官方文档的如下章节

            

    <result>

            非主键的映射规则

            <result column="dept_name" property="deptName"/>

    <association>

            属性:

                property:同<id>标签

                javaType:同<id>标签

                select:指定嵌套SQL,可以是本XML或者其他XML文件中的<select>

                fetchType:延迟加载,lazy打开延迟加载;eager积极加载

                column:同<id>标签

                resultMap:不使用嵌套SQL,而是使用复杂SQL一次取出关联的对象,并封装,对应下面的方式三

                resultSet:引用根据<select>标签得到的resultSets,如:

SELECT * FROM BLOG WHERE ID = #{id}

SELECT * FROM AUTHOR WHERE ID = #{id}
<select id="selectBlog" resultSets="blogs,authors" resultMap="blogResult" statementType="CALLABLE">
  {call getBlogsAndAuthors(#{id,jdbcType=INTEGER,mode=IN})}
</select>
<resultMap id="blogResult" type="Blog">
  <id property="id" column="id" />
  <result property="title" column="title"/>
  <association property="author" javaType="Author" resultSet="authors" column="author_id" foreignColumn="id">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="password" column="password"/>
    <result property="email" column="email"/>
    <result property="bio" column="bio"/>
  </association>
</resultMap>

                autoMapping:同<id>标签

                columnPrefix:关联多张表查询时,为了使列明不重复,使用此功能可以减少开发量

<select id="selectBlog" resultMap="blogResult">
  select
    B.id            as blog_id,
    B.title         as blog_title,
    A.id            as author_id,
    A.username      as author_username,
    A.password      as author_password,
    A.email         as author_email,
    A.bio           as author_bio,
    CA.id           as co_author_id,
    CA.username     as co_author_username,
    CA.password     as co_author_password,
    CA.email        as co_author_email,
    CA.bio          as co_author_bio
  from Blog B
  left outer join Author A on B.author_id = A.id
  left outer join Author CA on B.co_author_id = CA.id
  where B.id = #{id}
</select>

抽取出共同的resultMap,因为作者和其他作者都具有同样的属性,因此有:

<resultMap id="authorResult" type="Author">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
  <result property="password" column="author_password"/>
  <result property="email" column="author_email"/>
  <result property="bio" column="author_bio"/>
</resultMap>
<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author"
    resultMap="authorResult" />
  <association property="coAuthor"
    resultMap="authorResult"
    columnPrefix="co_" />
</resultMap>

                foreignColumn:外键列

                notNullColumn:不为空的列,如果指定了列,那么只有当字段不为空时,Mybatis才会真正创建对象,才能得到我们想要的值

                typeHandler:同<id>标签

            方式一:

  <!-- 嵌套方式 -->
  <resultMap type="com.jv.bean.Employee" id="EmpAndDeptMethod2">
  	<id column="employee_id" property="employeeId"/>
  	<result column="first_name" property="firstName"/>
  	<result column="last_name" property="lastName"/>
  	<result column="gendor" property="gendor"/>
  	<result column="birthday" property="birthday"/>
  	<!-- 可以将下面这部分抽离出来单独使用一个resultMap进行标记,然后在association标签中使用resultMap指向该标记 -->
  	<association property="dept" javaType="com.jv.bean.DepartMent">
	  	<id column="dept_id" property="deptId"/>
	  	<result column="dept_name" property="deptName"/>
	  	<result column="dept_desc" property="deptDesc"/>
  	</association>
  </resultMap>
  <select id="getEmployeeDetailInfo2" resultMap="EmpAndDeptMethod2">
	select employee_id,first_name,last_name,gendor,birthday,a.dept_id,dept_name,dept_desc 
	  	  from employee a,department b
	  	 where a.dept_id=b.dept_id
	  	   and a.employee_id=#{id}
  </select>

        方式二:

  <!-- 分布查询 -->
  <!-- 
  	该功能有一个很重要的用途:可以支持延迟加载(按需加载),需要在全局配置文件中增加: 
	  	lazyLoadingEnabled 打开延迟加载
	  	aggressiveLazyLoading 设置为TRUE是使用时全部加载,false是按需加载
  	这两个配置。
  -->
  
  
  <resultMap type="com.jv.bean.Employee" id="EmpAndDeptMethod3">
  	<id column="employee_id" property="employeeId"/>
  	<result column="first_name" property="firstName"/>
  	<result column="last_name" property="lastName"/>
  	<result column="gendor" property="gendor"/>
  	<result column="birthday" property="birthday"/>
  	<association property="dept"
		select="com.jv.dao.DepartMentMapper.getDepartMentByIdNew" column="dept_id">
  	</association>
  	<association property="post"
  		select="com.jv.dao.PostMapper.getPostById" column="post_id">
  	</association>
  </resultMap>
  <select id="getEmployeeDetailInfo3" resultMap="EmpAndDeptMethod3">
	select employee_id,first_name,last_name,gendor,birthday,dept_id,post_id
	  	  from employee a
	  	 where a.employee_id=#{id}
  </select>

        方式三:

  <!-- 嵌套方式 -->
  <resultMap type="com.jv.bean.Employee" id="EmpAndDeptMethod2">
  	<id column="employee_id" property="employeeId"/>
  	<result column="first_name" property="firstName"/>
  	<result column="last_name" property="lastName"/>
  	<result column="gendor" property="gendor"/>
  	<result column="birthday" property="birthday"/>
  	<!-- 可以将下面这部分抽离出来单独使用一个resultMap进行标记,然后在association标签中使用resultMap指向该标记 -->
  	<association property="dept" resultMap="deptMap">
  	</association>
  </resultMap>
  <resultMap id="deptMap" javaType="com.jv.bean.DepartMent">
	  	<id column="dept_id" property="deptId"/>
	  	<result column="dept_name" property="deptName"/>
	  	<result column="dept_desc" property="deptDesc"/>
  </resultMap>
  <select id="getEmployeeDetailInfo2" resultMap="EmpAndDeptMethod2">
	select employee_id,first_name,last_name,gendor,birthday,a.dept_id,dept_name,dept_desc 
	  	  from employee a,department b
	  	 where a.dept_id=b.dept_id
	  	   and a.employee_id=#{id}
  </select>

 

    <collection>

        和association很像,collection是负责处理多行的结果集,如:

        方式一:

        使用嵌套SQL

<resultMap id="blogResult" type="Blog">
  <collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
</resultMap>

<select id="selectBlog" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectPostsForBlog" resultType="Post">
  SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>

        方式二:

        使用复杂查询-在collection中直接配置封装规则

<select id="selectBlog" resultMap="blogResult">
  select
  B.id as blog_id,
  B.title as blog_title,
  B.author_id as blog_author_id,
  P.id as post_id,
  P.subject as post_subject,
  P.body as post_body,
  from Blog B
  left outer join Post P on B.id = P.blog_id
  where B.id = #{id}
</select>
<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <result property="body" column="post_body"/>
  </collection>
</resultMap>

        方式三:

        使用复杂查询-抽取封装规则放到resultMap中

<select id="selectBlog" resultMap="blogResult">
  select
  B.id as blog_id,
  B.title as blog_title,
  B.author_id as blog_author_id,
  P.id as post_id,
  P.subject as post_subject,
  P.body as post_body,
  from Blog B
  left outer join Post P on B.id = P.blog_id
  where B.id = #{id}
</select>
<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <collection property="posts" ofType="Post" resultMap="blogPostResult" columnPrefix="post_"/>
</resultMap>

<resultMap id="blogPostResult" type="Post">
  <id property="id" column="id"/>
  <result property="subject" column="subject"/>
  <result property="body" column="body"/>
</resultMap>

        方式二和方式三只有在封装的方式上有区别

    <descriminator>

        负责根据返回的字段的值封装不同的类型,如:

<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <result property="make" column="make"/>
  <result property="model" column="model"/>
  <result property="color" column="color"/>
  <discriminator javaType="int" column="vehicle_type">
    <case value="1" resultMap="carResult"/>
    <case value="2" resultMap="truckResult"/>
    <case value="3" resultMap="vanResult"/>
    <case value="4" resultMap="suvResult"/>
  </discriminator>
</resultMap>
<resultMap id="carResult" type="Car" extends="vehicleResult">
  <result property="doorCount" column="door_count" />
</resultMap>

     上面的配置就是如果vehicle_type的值是1,那么封装的结果为carResult,同事carResult又继承了vehicleResult的所有普通封装规则,最后的它结果可以按照下面的配置理解

<resultMap id="carResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <result property="make" column="make"/>
  <result property="model" column="model"/>
  <result property="color" column="color"/>
  <result property="doorCount" column="door_count"/>
</resultMap>

 

<constructor>

    使用构造器注入属性值,可能会问既然通过<id>和<result>就可以给属性注入值了,为什么还有一个构造器注入的,原因是有的JavaBean没有提供属性的getter和setter方法。

    

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

为了维护更方便,推荐在使用构造器注入的时候加上name属性,该属性值与构造器参数名字相同(需要编译参数加上-parameters,Jdk版本为1.8,而且Mybatis的参数useActualParamName设置为true(默认值为true)),也可以使用@param("paramName")指定特殊的参数名。

展开阅读全文
打赏
0
1 收藏
分享
加载中
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部